Flavien Volken
Flavien Volken

Reputation: 21289

Meteor: Publish a subset of another publication

I have a custom publication on my server (which in some way join 2 collections).

This resulting set of this publication is exactly what I need but for performances issues I would like to avoid sending it entirely to the client.

If I did not care about performances, I would only subscribe to the publication and do something like theCollection.find({"my":"filter"})

I am therefore trying to find a way to publish a subset of the custom publication so that the filter would be applied on the custom publication on the server side.

Is there a way to chain or filter publications (server side) ?

For the question we can assume the custom publication to look like this and cannot be modified:

Meteor.publish('customPublication', function() {
    var sub = this;

    var aCursor = Resources.find({type: 'someFilter'});
    Mongo.Collection._publishCursor(aCursor, sub, 'customPublication');

    sub.ready();
  });

Upvotes: 1

Views: 175

Answers (2)

Flavien Volken
Flavien Volken

Reputation: 21289

Ok I came to the following workaround. Instead of working on the publication, I simply added a new collection I update according to the other collections. In order to do so I am using the meteor hooks package

function transformDocument(doc)
{
doc.aField = "aValue"; // do what you want here
return doc;
}

ACollection.after.insert(function(userId, doc)
{
    var transformedDocument = transformDocument(doc);
    AnotherCollection.insert(transformedDocument);
});

ACollection.after.update(function(userId, doc, fieldNames, modifier, options)
{
    var transformedDocument = transformDocument(doc);
    delete transformedDocument._id;
    AnotherCollection.update(doc._id,{$set:transformedDocument});
});

ACollection.after.remove(function(userId, doc)
{
    AnotherCollection.remove(doc._id);
});

Then I have the new collection I can publish subsets the regular way

Benefits:

  • You can filter whatever you want into this db, no need to worry if the field is virtual or real
  • Only one operation every time a db changes. This avoid having several publication merging the same data

Cave eats:

  • This requires one more Collection = more space
  • The 2 db might not be always synchronised, there is few reasons for this:
    • The client manually changed the data of "AnotherCollection"
    • You had documents in "ACollection" before you added "AnotherCollection".
    • The transform function or source collection schema changed at some point

To fix this:

AnotherCollection.allow({
    insert: function () {
        return Meteor.isServer;
    },
    update: function () {
        return Meteor.isServer;
    },
    remove: function () {
        return Meteor.isServer;
    }
});

And to synchronise at meteor startup (i.e. build the collection from scratch). Do this only once for maintenance or after adding this new collection.

Meteor.startup(function()
{
    AnotherCollection.remove({});
    var documents = ACollection.find({}).fetch();
    _.each(documents, function(doc)
    {
    var transformedDocument = transformDocument(doc);
    AnotherCollection.insert(transformedDocument);
    });
});

Upvotes: 0

kaoskeya
kaoskeya

Reputation: 1091

if i understand the question right, you are looking for https://atmospherejs.com/reywood/publish-composite

It let's you "publish a set of related documents from various collections using a reactive join. This makes it easy to publish a whole tree of documents at once. The published collections are reactive and will update when additions/changes/deletions are made."

Upvotes: 1

Related Questions