meteor-publications

1.2.0 • Public • Published

Meteor Publications

A library to make creating powerful publications in Meteor easier to write and understand. This library also enables basic "relational" publications.

Installation

npm install --save @webantic/meteor-publications

Since there is no way to require meteor/meteor or meteor/mongo from npm, you must pass this in to the module at startup:

// publication.config.js
import { Meteor } from 'meteor/meteor'
import { Mongo } from 'meteor/mongo'
import init from '@webantic/meteor-publications'

const { Publication, RelationalPublication } = init(Meteor, Mongo)

export {
  Publication,
  RelationalPublication
}

Usage

All publications require:

  • a name which can be any string or null
  • an action which is a function that defines what data will be sent to the client.

A publication can also control access by setting one or more authenticate hooks. Access can be further controlled by setting one or more authorize hooks. Finally, publications have built-in support for the simple:rest package - options set on the rest object will be processed and passed to the simple:rest package.

Examples

A basic publication can be set up by supplying only a name and action:

const inkPub = new Publication({
  name: 'inks',
  action () {
    return Inks.find()
  }
})

The action handlers' contexts are equivalent to that of a standard Meteor publication handler's, but with the addition of two publication helpers; this.publish and this.relationalPublish:

const inkPub = new Publication({
  name: 'inks',
  action () {
    // All the standard properties and methods are available:
    this.userId
    this.added(/* collectionName, documentId, documentFields */)
    // etc...

    // Two additional methods are also available:
    this.publish(/* publicationConfig */) // a helper to publish a cursor to a client
    this.relationalPublish(/* publicationConfig */) // a helper to publish a cursor and related data to a client
  }
})

The Publish helper

Why?

One of the great things about Meteor publications is being able to return a cursor and have the associated documents be published to the client. When you need to publish more than one cursor from a single publication, things can get complicated quite quickly. The publish helper abstracts away a lot of this complexity, leaving you with more expressive publications.

How?

The publish helper takes a single object argument which contains the following properties:

  • {Mongo.Collection} collection The collection to query
  • {Object} selector The selector to query the collection with
  • {Object} [options] An optional set of query options (limit, sort, etc..)

N.B. You must manually call this.ready() once you have set up all your observers.

const inkPub = new Publication({
  name: 'inks',
  action () {
    this.publish({
      collection: BlueInks,
      selector: {},
      options: { limit: 5 }
    })

    this.publish({
      collection: BlackInks,
      selector: {},
      options: { limit: 5 }
    })

    this.ready()
  }
})

The RelationalPublish helper

Why?

Meteor's implementation of Mongo (currently) lacks support for aggregation pipelines, making it challenging to publish related data across multiple collections. This helper abstracts away the implementation, leaving more expressive publications.

How?

The relationalPublish helper takes a single object argument which contains the same properties as the publish helper, but with an additional one:

  • {Object[]} relations An array of objects with the following keys:
    • {Mongo.Collection} collection The collection where the related data resides
    • {string} foreignKeyName The name of the key on the main collection which contains the identifier for the related data
    • {string} [identifier] An optional identifier name on the related collection. Defaults to '_id'
    • {boolean} [reactive] An optional flag to specify whether to update which related data is published when changes occur in the main collection. Defaults to true
const penPub = new Publication({
  name: 'pens',
  action () {
    this.relationalPublish({
      collection: Pens,
      selector: { inkColor: 'blue' },
      relations: [{
        collection: Inks, // publish related data about inks
        foreignKeyName: 'inkColor', // use "inkColor" as the foreign key name on the Pens collection (always "blue" in this example)
        identifier: 'color' // The field to look for on the "Inks" collection
      }]
    })

    // This acomplishes the following:
    // we publish collection.find(selector) --- Pens.find({inkColor: 'blue'})
    // we take all the unique values found in the foreignKeyName ("inkColor") field of the resulting documents and publish relation.collection.find({[identifier]: {$in: <those values>}}) --- Inks.find({color: {$in: ['blue']}})

    this.ready()
  }
})

Authentication and Authorization

You can ensure that users are allowed access to the data a publication provides by setting authenticate and/or authorize hook(s):

const protectedPub = new Publication({
  name: 'protected',
  authenticate () {
    // context is the same as `action` handler
    return !!this.userId
  },
  // values can be either functions or arrays of functions
  authorize: [authHandler, otherAuthHandler],
  action () {
    
  }
})

The context is the same in these hooks as it is in the action handler. They also receive the same parameters. You may either return false or throw an error in an auth hook to prevent the execution of the action handler.

Package Sidebar

Install

npm i meteor-publications

Weekly Downloads

2

Version

1.2.0

License

ISC

Last publish

Collaborators

  • carlevans719