1.0.0 • Published 4 years ago

subscribe-for-data v1.0.0

Weekly downloads
4
License
MIT
Repository
github
Last release
4 years ago

subscribe-for-data

Fast implementation of multiple related models properties fetching & mixing to your model.

  • DB agnostic.
  • flexible query condition
  • one DB query per subscription.
  • all queries running parallel, starting at same moment, you choose then
  • No loops, stream based.
  • zero dependencies

Workflow description

You create subscription around your related model with makeSubscription(model, options)

You can create any count of subscriptions you need.

Then you can to subscription.add(target) target objects you want to mix in properties from related model data.

After you've added all needed targets to all subscriptions you can anytime run fillSubscriptions()

fillSubscriptions() assigns data as it goes via stream with auto parallelization if multiple subscriptions created. One query per subscription is executed.

It generates mongo condition. If you return from options.getCondition(target) scalar value then is generated $in query. I
to query your source,

Mongo query generation is just default behavior, you can alter it as you want.

Installation

npm i subscribe-for-data subscribe-for-data-from-mongoose

Import

const mongoosePlugin = require('subscribe-for-data-from-mongoose');
const { 
  makeSubscription, fillSubscriptions 
} = require('subscribe-for-data').use(mongoosePlugin);

Example

By default it works with mongoose. This behavior can be easily overriden by setting custom getStream option callback.

const mongoosePlugin = require('subscribe-for-data-from-mongoose');
const { makeSubscription, fillSubscriptions } = require('subscribe-for-data').use(mongoosePlugin);
const RootModel = require('./MainModel');
const RelatedModel = require('./RelatedModel');
const AnotherRelatedModel = require('./AnotherRelatedModel');

(async () => {
  const relatedSubscription = makeSubscription(RelatedModel, { // single field attach
    targetField: 'position', // key of property to be created on roots
    foreignField: 'root_id', // field to build condition against
    sourceField: 'position'
  });
  const anotherRelatedSubscription = makeSubscription(AnotherRelatedModel, { // something completely different
    getCondition({ mysteriousTimestamp, type }) {
      return { type, updatedAt: { $gt: mysteriousTimestamp} };
    }, 
    assignData(root, { someField, otherType }) {
      (root.someFields = root.someField || []).push(someField);
      (root.otherTypes = root.otherTypes || new Set()).add(otherType);
    },
  });
  const roots = [];
  await RootModel.find({}).cursor().eachAsync((root) => {
    [relatedSubscription, anotherRelatedSubscription]
      .forEach(subscription => subscription.add(root)); // subscribed
    roots.push(root);
  });
  await fillSubscriptions(); // 2 DB queries executed in parallel, no loops then
  console.log(roots[0]);
})();

Expected output:

{
  "_id": "000000",
  "position": 42,
  "someFields": [2, 5, 8, 5],
  "otherTypes": [23, 42, 78]
}

API Reference

SubscribeForData : object

subscribe-for-data

SubscribeForData.makeSubscription(source, options) ⇒ Object

Creates subscription for related model data

ParamTypeDescription
sourceObjectSource model
optionsObjectOptions
options.targetFieldStringfield data to be saved into (optional)
options.baseConditionObjectBase condition
options.defaultValue*Default value for field
options.getKeygetKeyCallback which returns unique key from target model (model.id by default)
options.getConditiongetConditionreturns condition, using target model (model.id by default)
options.extractKeyextractKeyreturns unique key of target model from foreign model
options.isMultipleBooleanif one to many relation
options.useEachAsyncBooleanonly for mongoose cursor
options.parallelNumberparallel parameter for eachAsync if useEachAsync is true
options.foreignFieldStringIf getCondition returns scalar values this field will be used for $in
options.sourceFieldStringfield to use of foreign model
options.assignDataassignDataDo model filling by itself, otherwise use targetField
options.getStreamgetStreamreturns stream from source and condition (using mongoose model by default)
options.getDataHandlergetDataHandlerGet data handler for processing related models
options.getAddingMethodgetAddingMethodGet add() method of future subscription

SubscribeForData.fillSubscriptions() ⇒ Promise

Fill subscribed targets

SubscribeForData.assignDefaultOptions(mixin)

change default options

Param
mixin

assignData : function

Assigns data from foreign model to target

ParamTypeDescription
targetObjectyour target model
foreignObjectforeign model

getKey ⇒ *

get unique identifier of target for internal indexing

Returns: * - target identifier

ParamTypeDescription
targetObjectyour target model

extractKey ⇒ *

get unique identifier of target from foreign model

Returns: * - target identifier

ParamTypeDescription
foreignObjectForeign model data

getCondition ⇒ *

get condition

Returns: * - condition, can be scalar or object

ParamTypeDescription
targetObjectyour target model

getDataHandler ⇒ function

get foreign data handler

Returns: function - Callback handling data assignment

ParamTypeDescription
optionsObjectOptions
options.targetsObjecttargets index
options.targetFieldStringfield data to be saved into
options.extractKeyextractKeyreturns unique key of target model from foreign model
options.isMultipleBooleanif one to many relation
options.sourceFieldStringfield to use of foreign model
options.assignDataassignDataDo model filling by itself, otherwise use targetField

getAddingMethod ⇒ function

get future subscription.add() method

Returns: function - Callback handling data assignment

ParamTypeDescription
optionsObjectOptions
options.targetsObjecttargets index
options.getKeygetKeyCallback which returns unique key from target model (model.id by default)
options.getConditiongetConditionreturns condition, using target model (model.id by default)
options.defaultValue*Default value for field
options.targetFieldStringfield data to be saved into
options.conditionobjectDB Query condition, being prepared
options.extractKeyextractKeyreturns unique key of target model from foreign model
options.foreignFieldStringIf getCondition returns scalar values this field will be used for $in
options.innerArrayInternal array for condition storing

getStream : function

get stream from model using condition

ParamDescription
sourceSource model
conditionQuery condition