universe:collection

v2.9.1Published 6 years ago

This package has not had recent updates. Please investigate it's current state before committing to using it in your project.

Universe Collection

Universe Collections allows you to extend Meteor's Mongo.Collection functionality by allowing you to define your own remote collection methods, add document helpers using a simple helpers method, and create new classes inherited from UniCollection.UniDoc.

Features:

  • Remote (RPC) methods on documents and collections
  • Multi-schema support
  • Hooks for many methods (e.g. insert, update, remove, your own rpc methods, etc.)
  • Document helpers (e.g. update from doc, doc.save(), user.getName())
  • EJSON serialization of documents
  • Mixins for collections
  • Compatibility with argument-audits-check
  • Aggregations on client and server
  • Allow/Deny for any rpc methods (not just insert/update/remove)

And many more useful features.

The current version supports Meteor 1.6.1

To use Meteor lower than 1.6.0 please install the last version of 2.8.x

To use Meteor 1.2 please install the last version of 2.2.x

All documents know what collection they belong to and you can easily get a collection from any document as well as make a document update like this:

1doc.update({$set: {title: 'new title'}});
2doc.call('addItem', item);

Becase this is an EJSONable document type, you can use them with Meteor's built-in Session and ReactiveDict features.

UniCollection inherits from Mongo.Collection, but does not change the original Mongo.Collection code. The SimpleSchema integration allows you to attach a schema to your collection and validate against your chosen (or a default) schema.

Table of Contents

Installation

    $ meteor add universe:collection

How to use

Creating a collection

Instead of using the Meteor standard:

1Colls.Books = new Mongo.Collection('Books');

use this:

1 Colls.Books = new UniCollection('Books');

A Universe collection, unlike a Meteor Collection, must alway have name. If you want to create a local collection please pass in an options property: connection: null, instead of null as the first parameter.

Methods on a collection object

  • setDocumentClass(transformationObject)

This sets a transformation function for collection. The function is passed as an argument and will be executed for each document to transform the selected documents before the method (such as: find, findOne) returns the document.

UniDoc is a default of document prototype. (You can also pass it in collection constructor in options as a key 'setDocumentClass')

1    var collection = new UniCollection('some');
2
3    // getting new prototype of UniDoc
4    var myDocProto = UniDoc.extend();
5
6    //Adding new method to prototype of myDoc.
7    myDocProto.prototype.getTitleUppercase = function(){ return this.title.toLocaleUpperCase(); }
8
9    //setting new prototype to collection
10    collection.setDocumentClass(myDocProto);
11
12    var docInstance = collection.findOne();
13    console.log(docInstance.getTitleUppercase());
  • docHelpers(objectWithMethods)

Using this method you can add new helpers function to the document prototype as an alternative to setDocumentClass. All of these methods will be added to the returned document by function find, findOne. Documents helpers do not depend on transformationObject. You can find more details in the helpers section.

1    var collection = new UniCollection('some');
2    collection.docHelpers({
3          getTitleUppercase: function(){
4                return this.title.toLocaleUpperCase();
5          }
6    });
7
8    var docInstance = collection.findOne();
9    console.log(docInstance.getTitleUppercase());
  • create Creates new instance of a document for the current collection. The create method accepts the arguments rawDoc, options.
1// empty not saved instance of doc
2    var docInstance = collection.create();
3// warning: some of methods cannot work properly without some fields
4    console.log(docInstance.getCollectionName());

You can pass a raw object document and either save it after the function returns or it at the moment of creation, by passing an options parameter.

1//  not saved instance of doc
2    var docInstance = collection.create({title: 'abc'});
3// manual save
4    docInstance.save();
5// saving it in the moment of creation
6 var docInstance2 = collection.create({title: 'abcd'}, true);
7// saving it in the moment of creation with different schema
8  var docInstance3 = collection.create({title: 'abcde'}, {save: true, useSchema: 'schemaName'});
  • methods

Remote methods on collection that can be invoked over the network by clients from collection instance. From UniCollection you can define and call remote methods (just like Meteor.methods and Meteor.call). Additionally, handler will be have in context a collection object under this.collection. Rest things like userId, connection are same as handlers in Meteor.methods have.

  • docMethods

Remote methods on document that can be invoked over the network by clients from document instance.

  • hasDocument(docOrId)

Checks if document belongs to this collection

  • setDefaultSort(options)

Adds default sort options to find, but default sort option are used only when someone call find without sort options

1    Colls.Books.setDefaultSort({ title: 1 })
  • ensureUniDoc(docOrId, additionalPattern, errorMessage=)

This method gives warranty that returned object is document of current collection but if this method cannot return a proper document it will throw error You can provide additional Match.* patterns as a supplement of this.matchingDocument()

  • docOrId {UniCollection.UniDoc|String|*} document or id of available document that satisfies pattern
  • additionalPattern {Object=} Additional regiments that mast be checked.

If true is passed under this argument, then this method will fetch fresh data even if document is correct.

  • errorMessage {String=undefined} Custom message of error

Ensures that returned document is matched against pattern.

1    var book = Colls.Books.ensureUniDoc(book);
2    var book =  Colls.Books.ensureUniDoc(bookId);

This function works on top of meteor match and can be safely used with audit-argument-checks package More: (meteor match patterns)[http://docs.meteor.com/#matchpatterns]

  • matchingDocument(keysPatterns=)

Pattern argument to checking functions like: this.ensureUniDoc(), check() and Match.test()

Basic pattern checks document type if type is equal to current constructor of documents in this collection.

Additionally you can precise patterns for fields of document, using keysPatterns

1    var book =  Colls.Books.ensureUniDoc(book, Colls.Books.matchingDocument({title: String}));
2    // or 
3    Match.test(Colls.Books.matchingDocument({title: String}));
4    // or
5    check(doc, Colls.Books.matchingDocument());
  • ensureMongoIndex(indexName, keys, options = {})

Creates an index on the specified field if the index does not already exist. If universe detects,that index under name is changed, mechanism will drop the old index under name passed as first parameter to this function.

  • Params
  • {string} indexName Unique name of index for this collection
  • {object} keys An Object that contains the field and value pairs where the field is the index key

and the value describes the type of index for that field. For an ascending index on a field, specify a value of 1; for descending index, specify a value of -1.

  • {object} options Optional. A document that contains a set of options that controls the creation of the index.

  • dropMongoIndex(indexName)

Drops the specified index from a collection.

Aggregations

const result = myUniCollection.aggregate([
    {'$match': {age: 23}},
    {'$group':{_id:'$student_id', score:{$min:'$score'}}},
    {'$sort':{_id: 1, score: 1}}
]);

console.log(result);

Server side

Exposing .aggregate method on UniCollection instances. There is no oberserving support or reactivity built in on server side.

Client side

Performs aggregation operation using the aggregation pipeline. Reactivity is based on observation matched elements from first step

Note: If you want to use aggregation on client side You will need to install mingo (^0.7.0) in project. npm install -save mingo

Client side aggregation operators

  • Pipeline Operators ($group, $match, $project, $sort, $limit, $unwind, $skip)
  • Group Operators ($addToSet, $sum, $max, $min, $avg, $push, $first, $last)
  • Projection Operators ($elemMatch, $slice)
  • Arithmetic Operators ($add, $divide, $mod, $multiply, $subtract)
  • Array Operators ($size)
  • Boolean Operators ($and, $or, $not)
  • Comparisons Operators ($cmp, $gt, $gte, $lt, $lte, $ne, $nin, $in)
  • Conditional Operators ($cond, $ifNull)
  • Date Operators ($dayOfYear, $dayOfMonth, $dayOfWeek, $year, $month, $week, $hour, $minute, $second, $millisecond, $dateToString)
  • Literal Operators ($literal)
  • Set Operators ($setEquals, $setIntersection, $setDifference, $setUnion, $setIsSubset, $anyElementTrue, $allElementsTrue)
  • String Operators ($strcasecmp, $concat, $substr, $toLower, $toUpper)
  • Variable Operators ($map, $let)

Schemas

UniCollection allows you to attach one or more schemas to collection. Every insert and update from client or server code will be automatically validates against schema. You can choose for inserting and updating a different schema than default by options.

This package requires and automatically installs the aldeed:simple-schema package, which defines the schema syntax and provides the validation logic.

Default schema for a Collection

1collection.setSchema(new SimpleSchema({
2    title: {
3        type: String,
4        label: "Title",
5        max: 200
6    },
7    author: {
8        type: String,
9        label: "Author"
10    }
11}));
12
13// or
14
15collection.setSchema('default', new SimpleSchema({
16    title: {
17        type: String
18    },
19    author: {
20        type: String,
21        label: "Author"
22    }
23}));
24//getting default schema
25collection.getSchema()
26//or
27collection.getSchema('default')

Now that our collection has a schema, we can do a validated insert on either the client or the server:

1collection.insert({title: "Ulysses", author: "James Joyce"}, function(error, result) {
2  //The insert will fail, error will be set,
3  //and result will be undefined or false because "copies" is required.
4  //
5  //The list of errors is available on `error.invalidKeys` or by calling collection.getSchema().namedContext().invalidKeys()
6});

Or we can do a validated update:

1collection.update(book._id, {$unset: {copies: 1}}, function(error, result) {
2  //The update will fail, error will be set,
3  //and result will be undefined or false because "copies" is required.
4  //
5  //The list of errors is available on `error.invalidKeys` or by calling collection.getSchema().namedContext().invalidKeys()
6});

Additional schemas for a Collection

1collection.setSchema('expanded_schema', new SimpleSchema({
2    title: {
3        type: String,
4        label: 'Title',
5        max: 200
6    },
7    'co-authors': {
8        type: String,
9        optional: true
10    },
11    summary: {
12        type: String,
13    }
14}));
15//getting additional schema
16collection.getSchema('expanded_schema')

Our collection has a secondary schema, we can do a validated insert by that schema:

1collection.insert({title: "Ulysses", author: "James Joyce"}, {useSchema: 'expanded_schema'}, function(error, result) {
2  //The insert will fail, error will be set,
3  //and result will be undefined or false because "copies" is required.
4  //
5  //The list of errors is available on `error.invalidKeys` or by calling collection.getSchema('expanded_schema').namedContext().invalidKeys()
6});

Or we can do a validated update by that schema:

1collection.update(book._id, {$unset: {copies: 1}}, {useSchema: 'expanded_schema'}, function(error, result) {
2  //The update will fail, error will be set,
3  //and result will be undefined or false because "copies" is required.
4  //The list of errors is available on `error.invalidKeys` or by calling collection.getSchema('expanded_schema').namedContext().invalidKeys()
5});

Passing Options

In Meteor, the update function accepts an options argument. UniCollection changes the insert function signature to also accept options in the same way, as an optional second argument. Whenever this documentation says to "use X option", it's referring to this options argument. For example:

1collection.insert(doc, {useSchema: schemaName});

Like we see, you can choose schema by the key named "useSchema" provided in options for update and insert.

Additional SimpleSchema Options

In addition to all the other schema validation options documented in the simple-schema package, the UniCollection package adds additional options uniUI in this section.

Remote methods

UniCollection provides remote methods on collections and documents. This works like Meteor.methods, Meteor.call, Meteor.apply but it works on collection and document.

Remote methods on collection

This kind of methods can be invoked over the network by clients from collection instance. From UniCollection you can define and call remote methods (just like Meteor.methods and Meteor.call). Additionally, handler will be have in context a collection object under this.collection. Rest things like userId, connection are same as handlers in Meteor.methods have.

Remote methods on collection are inspired by insert/update function and all of them have callbacks for allow/deny methods. Which are called on invocation, but only first method in single invocation stack is validated. It mean that one function on server side calls another, "allow/deny" validation will be checked only for first one.

1    var collection = new UniCollection('some');
2    collection.methods({
3        noneDirectly: function(){
4            console.log('called by other');
5        },
6        getX: function(a, b, c){
7            console.log(a, b, c);
8        },
9        getY: function(){
10            if(Meteor.isServer){
11               return this.collection.call('noneDirectly');
12            }
13        }
14    });
15    //also you can provide callbacks for deny function
16    collection.allow({
17        //value of document variable will be null for remote collection methods
18        getX: function(userId, document, args, invocation){
19            return true;
20        },
21        //only for remote methods from document will be have object of doc in this argument
22        getY: function(userId, document, args, invocation){
23                return true;
24        }
25    });
26    //call with params
27    collection.call('getX', 1, 2, 3);
28    //Invoke a method passing an array of arguments.
29    collection.apply('getX', [1, 2, 3]);
30    //calling with callback
31    collection.call('getY', function(error, result){ console.log(error, result); });

Take a look that rules for Allow/Deny can be added only when method for given rule is already created for universe collection or document.

So, you cannot set rules allow or deny before collection.methods, or collection.docMethods.

Remote methods on document

You can define methods that will be available to invoke over the network from document instance.

Works in the same way as collection.methods but additionally handler will be have a document object in context (this.document)

1    var collection = new UniCollection('some');
2    collection.docMethods({
3        addItem: function(item) {
4            console.log('Called from doc: ', this.document._id);
5            return this.document.update({$set: {item: item}});
6        }
7    });
8    //also you can provide callbacks for deny function
9    collection.allow({
10        addItem: function(userId, document, args, invocation) {
11            check(args, [String]);
12            return true;
13        }
14    });
15
16    var doc = collection.findOne();
17    doc.call('addItem', 'someItem', function(error, result){ console.log(error, result); });

Documents Helpers

You can add new methods for transforming documents in two ways

Simple way:

You can use Collection.helpers method to register new methods to objects.

1    Colls.Books = new UniCollection('Books');
2
3    //Adding methods to documents
4    Colls.Books.docHelpers({
5        read: function(){
6            this.isReaded = true;
7            this.save();
8        }
9    });

And after that you can use it:

1var book = Colls.Books.findOne();
2//All documents will be have before defined functions
3book.read();

By Inheritance:

Inheritance takes place by calling extend() method on other UniDoc object

1    //Gets your new independent prototype
2    var YourDocProto = UniCollection.UniDoc.extend();
3
4    //Defines your own methods available only in prototype of YourDocProto
5    YourDocProto.prototype.getName = function () {
6        if (this.name) {
7            return this.name;
8        }
9        return 'unknown';
10    };
11
12    Colls.Books.setConstructor(YourDocProto);

Note that: Methods added by docHelpers methods always are on the top of inheritance. You can change object class for document but methods added by docHelpers always are accesible.

Example use within a blaze template

Methods on document you can use instead template helpers: This can help you of avoiding unnecessary template helpers

1Template.books.helpers({
2    books: function() {
3    return Colls.Books.find();
4    }
5});

with the corresponding template:

1<template name="books">
2    <ul>
3        {{#each books}}
4            <li>{{title}} by {{owner.getName}}</li>
5        {{/each}}
6    </ul>
7</template>

Hooks

sync hooks: 'find','findOne','setSchema','create' with async support: 'insert','update','remove', 'upsert' hooks can be added for all remote methods on collection and documents

  • onBeforeCall(hookName [, idName], method, isOverride=false)
  • onAfterCall(hookName [, idName], method, isOverride=false)

Removing unnecessary hooks

  • offBeforeCall(hookName, idName)
  • offAfterCall(hookName, idName)

Example

var col = new UniCollection('some');

col.onBeforeCall('insert', 'myAwesomeInsert', function(doc){
  console.log('will be inserted', doc, 'to collection:', this.getCollection());
});

col.onBeforeCall('update', 'myAwesomeUpdate', function(selector, modifier, options){
  this.oldDoc = this.getCollection().findOne(selector);
});

col.onAfterCall('update', 'afterAwesomeUpdate', function(selector, modifier, options){
  console.log('Old doc:', this.oldDoc, 'new doc:', this.getCollection().findOne(selector));
});

coll.insert({title: 'Awesome doc'});

coll.update({title: 'Awesome doc'}, {$set: {title: 'Much more awesome doc'}});

coll.offBeforeCall('insert', 'myAwesomeInsert');

coll.insert({title: 'Awesome doc2'});

Context of hook handler

Shared context

Context of all hooks is shared. It mean that you can add something in before hook and read it in onAfterCall.

collection.update({_id: 'a23df2c5dfK'}, {$set: { title: 'something'}});
collection.onBeforeCall('update', 'myGreatHook', function(selector, modifier){
    this.doc = collection.findOne(selector);
});

collection.onAfterCall('update', 'myGreatHookAfterUpdate', function(){
    console.log('before update doc looked like this', this.doc);
});

Stuff in context

Helpers

  • getCollection() Collection instance
  • getMethodName() Hook for method
  • getMethodContext() Context of method for which is hook
  • callDirect() Direct access to method (without any hooks)
  • isAfter() It tells if hook is after or before
  • currentHookId current idName of hook

Available only in before hooks, that can be potentially async methods (like insert/update/remove)

  • getCallback() It returns callback function if exists
  • setCallback() It sets new callback for async method

Available only in after hooks

  • getResult() gives returned value of executed method

Specific Helpers

Some of functions like update, upsert, have a additional special helpers in context.

  • getPreviousDocs() is available for hooks of update, upsert and remove

This method returns all documents that are selected by selector to current action.

  • getFields() is available for hooks of update and upsert methods

And returns an array of top level fields, which will be changed by modificator.

  • getPreviousDoc() is available for hooks of all remote methods attached to the document.

Returns fetched document, that is bound with method.

Additional useful helpers in UniUtils (in package: universe:utilities)

  • UniUtils.getFieldsFromUpdateModifier(modifier)

Gets array of top-level fields, which will be changed by modifier (this from update method)

  • UniUtils.getPreviewOfDocumentAfterUpdate(updateModifier, oldDoc = {})

Gets simulation of new version of document passed as a second argument

Direct call without hooks

Any call of method inside of collection.withoutHooks(function, list), will be called (as a default) without hooks. You can pass a list of hooks that should be omitted. Some special words can deactivate group of hooks like BEFORE, AFTER or ALL (what is default)

Example:

myCollection.withoutHooks(function () {
     myCollection.update('abc234', {$set: {title: 'Updated without hooks!'}})
});

Arguments passed to hook

Hook handler has the same parameter as are passed for method. Only callbacks passed as last argument are provided by this.getCallback() instead of be in arguments.

collection.onBeforeCall('update', 'argumentsLogger', function(selector, modifier, options) {
   console.log('argumentsLogger', selector, modifier, options).
});

Mixins

Simple way to extend your collection in new features.

Mounting

To add some mixin to collection, just create new instance of mixin class and pass them to as a item of array, under key mixins in options of UniCollection constructor.

myColl = new UniCollection('myColl', {
    mixins: [
        new UniCollection.mixins.BackupMixin({expireAfter: 86400}),
        new UniCollection.mixins.PublishAccessMixin(),
        new UniCollection.mixins.ShowErrorMixin()
    ],
});

As you can see some of mixins can have own options, that can be passed to constructor.

Attached mixins in this package

BackupMixin

This mixin provides backup functionality to your collection. Backup is stored in collection.backupCollection. By default, it is fully automatic, so when any document is removed, you can easily restore it. Example is available here.

Mixin provides also support for TTL indexes, so backup can be automatically removed - set expireAfter to desired time (in seconds).

Options
  • name, default 'Backup' - backup collection suffix
  • expireAfter, default false - time to expire (in seconds) - false mean no expiration
  • backupOnRemove, default true - if true, performs .backup() before remove
  • removeOnRestore, default true - if true, removes data from backup after .restore()
  • upsertOnRestore, default false - if true, .restore() performs .upsert(), .insert() otherwise
API
  • collection.backup([selector]) copies docs to collection.backupCollection
  • collection.restore([selector], [options]) copies docs back from collection.backupCollection
Example
1collection = new UniCollection('collection', {
2    mixins: [
3        new UniCollection.mixins.BackupMixin()
4    ]
5});
6
7collection.insert({number: 1});
8collection.insert({number: 2});
9collection.insert({number: 3});
10
11collection.find().count(); // 3
12collection.remove();       // all documents are copied to collection.backupCollection
13collection.find().count(); // 0
14collection.restore();      // all documents are copied to collection
15collection.find().count(); // 3

PublishAccessMixin

PublishAccessMixin adds access control to UniCollection.publish This works like insert or update, to collection.allow and collection.deny will be added new validator named "publish"

Example
 collection.allow({
       publish: function(userId, doc, publicationName){
           return true;
      }
  });
 
  collection.deny({
       publish: function(userId, doc, publicationName){
           return doc.ownerId !== userId;
       }
  });
Parameters
  • {string} userId The user 'userId' wants to subscribe document 'doc' from this collection.
  • {object} doc document that might be published
  • {string} publicationName name of publication if is available.

Return true if this should be allowed. WARNING: This rule will be respected only by 'UniCollection.publish', Meteor.publish is expected to do their own access to checking instead relying on allow and deny.

ShowErrorMixin

Gets errors (if are) from insert, update, upsert, remove and passing them to show error function

new ShowErrorMixin(params={})
params:
      name - name of mixin
      errorDisplayer - function that will be responsible as a showing the error message,
      like e.g. showError(exceptionOrString) // if function is not declared, as a default it will try use UniUI.setErrorMessage, if missing fallback to alert() 
      addForMethods: //Adds only for this one
          insert: true, upsert: true, update: true, remove: true
          (as a value can be passed a custome function of errorDisplayer)

Creating own mixin

There are two ways. One of them is just simple using inheritance by es6 from abstract class UniCollection.AbstractMixin

class MyNewMixin extends UniCollection.AbstractMixin {

    constructor({name = 'MyNewMixin', ...params} = {}) {
        super(name);
    }

    mount(collection, options = {}) {
        // do something on mount to collection
    }
}

But if you don't use es6 or you want different, there is another way (using of UniCollection.createMixinClass)

var MyNewMixin = UniCollection.createMixinClass({
    name: 'MyNewMixin',
    mount(collection, options = {}) {
        // do something on mount to collection
    }
});

Collection when attaches a mixin to self, it launches method mount on mixin where pass self as a first argument and self options as a second one.

EJSONable document types

Every constructor of documents, is registering as new EJSON type. It is made under name collectionName+"Doc"

Because of that Meteor is able to use types of universe document in:

fully allowing your type in the return values or arguments to methods. storing your type client-side in Minimongo. allowing your type in Session variables, ReactiveDict and other places.

Default methods on UniCollection.UniDoc

(They are default on each universe document)

  • extend()

    prepare copy of prototype UniDoc, to separate your future methods from base UniDoc

  • update(modifier, options, cb)

    Performs update on current document

    It works like update on collection but without first parameter

    (which is an id of current document)

  • remove(options, cb)

    Performs remove on current document

  • save(options, cb)

    Saves all or chosen keys in current document. options.fieldsList, options.useSchema or pass fieldsList instead options

  • refresh()

    refind doc and refresh fields in current document

  • findSelf()

    returns fresh instance of current document

  • getCollection() returns collection to which current document belongs.

UniUsers

( extension of Meteor.users )

Universe provides UniUsers object which is a copy of Meteor.users collection object that shares the same document with. Meteor.users collection stay unmodiefied. Both operates on the same documents, only methods to access objects have changed.

Methods on UniUsers

  • UniUsers.getLoggedInId()

    Gets the current user id, or null if no user is logged in. A reactive data source.

    It works in publish functions (difference to Meteor.userId())

  • UniUsers.getLoggedIn()

    Gets the current user record, or null if no user is logged in. A reactive data source.

    It works in publish functions (difference to Meteor.userId())

  • UniUsers.isAdminLoggedIn()

    Checks if the current user is an admin

    It is depended on user method user.isAdmin()

  • UniUsers.ensureUniUser(user, patternForMatch, errorMessage)

Same as Colls.Books.ensureUniDoc but as a default it takes the logged in user,

but only if first parameter is undefined.

So, something like that can prevent: UniUsers.ensureUniUser(user||null)

  • UniUsers.hasDocument(docOrId)

    Checks if document belongs to UniUsers collection

    (on client side you must have this doc in minimongo [subscription needed])

  • UniUsers.runWithUser = (userId, func, args, context) (server only)

    Adds a posibility of run function on server side as a user. So, UniUsers.getLoggedIn() and UniUsers.getLoggedInId() will be working correctly.

Documents methods on user object

  • getName() returns profile.name of user

  • getFirstEmailAddress() returns first email address

  • isLoggedIn() checks if this user is logged in (works on client and publication)

  • isAdmin() checks if user has flag is_admin === true (You can override this method in UniUsers.UniUser and checks something else)

Publications (UniCollection.Publish)

Of course this package works great with standard meteor publication mechanism. But if you want something more, this package provides additional mechanism for it. UniCollection.published works just like Meteor.publish but has a few additional stuff.

  • Simple mappings of relations or possibility of access control (by mixin)
  • Another benefit is that UniCollection.publish can be dynamically changed (redeclared)
  • Possibility of setting by options accessibility like: publication is only for users or only for admins.

No more checking if(!this.userId){ this.ready(); return;}

Simple way

UniCollection.publish('example', function() {
    return [Colls.MyColl.find(), Colls.Books.find()];
});

You can return one Collection.Cursor, an array of Collection.Cursors. If a publish function does not return a cursor or array of cursors, it is assumed to be using the low-level added/changed/removed interface, and it must also call ready once the initial record set is complete.

Parameters

  • name Name of the record set.

If null, the set has no name, and the record set is automatically sent to all connected clients (if you use mixin "PublishAccessMixin" then with access control)

  • handler {Function} Function called on the server each time a client subscribes.

Inside the function, this is the publish handler object, described below. If the client passed arguments to subscribe, the function is called with the same arguments.

options {Object}

  • override {boolean} resets handler for publication name. (only named publication can be overridden)
  • userOnly {boolean} publication will be available only for users
  • adminOnly {boolean} publication will be available only for admins

Low-level publish api

UniCollection.publish('example', function() {
    var self = this;
    var handle = Colls.Books.find({roomId: roomId}).observeChanges({
        added: function (id, fields) {
            self.added("books", id, fields);
        },
        changed: function (id, fields, allowedFields) {
            self.changed("books", id, fields);
        },
        removed: function (id, fields) {
            self.removed("books", id);
        }
    });
    self.onStop(function () {
        handle.stop();
    });
});
  • allowedFields Dictionary of fields possible return or exclude from it. ( They should be the same as was passed to options.fields in find() method. ) You can get allowed/excluded fields directly from cursor:

Server side: var allowedFields = cursor._cursorDescription.options.fields

Using with build-in mappings

This package provides simple way mapping mechanism. You must return base collection or collections and using method setMappings, define relational mappings

UniCollection.publish('example', function() {
    this.setMappings(Colls.MyColl, [
        //Map a value of organisationsIds from selected documents of Colls.MyColl to document from Colls.Rooms
        {
            key: 'organisationsIds',
            collection: Colls.Rooms
        },
        //Map ids of selected document of Colls.MyColl to document from Meteor.users where orgIds = id
        {
                    key: 'orgIds',
                    collection: Meteor.users,
                    reverse: true // reverse direction of the relationship (inverse relationship is more complex)
        }
     ]);
    //For mapped users you can map another documents
    this.setMappings(Meteor.users, [
            {
                key: 'organisationsIds',
                collection: Colls.Rooms,
                reverse: true

            }
    ]);
    //And another....
    this.setMappings(Colls.Rooms, [
        {
            key: 'roomId',
            reverse:true,
            collection: Colls.Documents,
            options: {fields: { title: 1 }}
        }
    ]);

    return Colls.MyColl.find();
});

Accessibility for users

users only

UniCollection.publish('example', function() {
    return Colls.Books.find();
}, {userOnly:true});

admins only

UniCollection.publish('example', function() {
    return Colls.Books.find();
}, {adminOnly:true});

Support for Universe modules

import {UniCollection, UniUsers, UniDoc, UniUser, BackupMixin, PublishAccessMixin} from 'meteor/universe:collection';

Additional extensions for this package

Integration with attendant third party packages

If you have problems with integration collection2 or collection-hooks

check it out following package:

universe:fixes-for-third-party-packages

Copyright and license Code and documentation © 2015 Vazco.eu Released under the MIT license.

This package is part of Universe, a package ecosystem based on Meteor platform maintained by Vazco. It works as standalone Meteor package, but you can get much more features when using the whole system.