Permalink
Fetching contributors…
Cannot retrieve contributors at this time
97 lines (73 sloc) 2.87 KB

Outside Mutations

There may be scenarios where you have an external service that is not Meteor, which performs mutations to MongoDB. If you want your subscriptions to "catch" the changes you have to send manually the changes to redis channels.

However, this is pretty straight forward.

Given I have the following publication:

return Tasks.find({groupId});

If an outside worker updates the MongoDB, it should also send changes to redis like this:

// update task document, that changes status inside MongoDB
redis.publish('tasks', JSON.stringify({
    e: 'u',
    d: {_id: taskId},
    f: ['status']
}))

tasks represents the name of the collection inside MongoDB and the message is a JSON string that can be parsed by the query processors.

These constants are described inside RedisPipe and Events here

If you plan on using this I suggest you copy it to your own constants, transforming the code like this:

redis.publish('tasks', JSON.stringify({
   [RedisPipe.EVENT]: Events.UPDATE,
   [RedisPipe.DOC]: {_id: taskId},
   [RedisPipe.FIELDS]: ['status']
}))

You have to be careful, if in your app you subscribe by _id:

return Task.find({_id: taskId})

In order for the processor to catch the event you have to send it to the tasks::taskId channel, where taskId represents the actual id inside MongoDB.

So, if you have both types of publications, you have to publish it to both tasks and tasks::taskId channels inside redis.

If you use namespaces, the channels also change:

return Task.find({groupId}, {
    namespace: `group::${groupId}`
})

This type of query will listen to group::groupId::tasks, this means that if you want to trigger reactivity for this query, you have to send it to both group::groupId::tasks and tasks::taskId, where groupId and taskId represent the actual ids inside MongoDB.

Keep in mind, that namespaces don't affect direct query processing:

return Task.find({_id: taskId}, {
    namespace: `group::${groupId}`
})

This type of subscription will bypass namespacing, and listen to only task::taskId

You can also trigger inserts and removes. The same rules for namespacing and direct processing applies.

redis.publish('tasks', JSON.stringify({
  [RedisPipe.EVENT]: Events.INSERT,
  [RedisPipe.DOC]: {_id: taskId},
}))
redis.publish('tasks', JSON.stringify({
  [RedisPipe.EVENT]: Events.REMOVE,
  [RedisPipe.DOC]: {_id: taskId},
}))

If you are using .rawCollection() to perform some MongoDB specific operations, then you have to manually push things to Redis, using the same strategies specified above:

import {getRedisPusher, Events, RedisPipe} from 'meteor/cultofcoders:redis-oplog';

getRedisPusher.publish('tasks', EJSON.stringify({
    [RedisPipe.DOC]: {_id: taskId},
    [RedisPipe.EVENT]: Events.UPDATE,
    [RedisPipe.FIELDS]: ['status']
});