meteor-feature-requests
meteor-feature-requests copied to clipboard
Filter documents by subscription (a.k. find from publication)
In my current project, I have multiple subscriptions, publishing their content to the same collection on the client side (since they are also managed on the same collection on the server side). This problem is also noted here: https://www.discovermeteor.com/blog/pagination-problems-meteor/#problem-2:-subscription-ownership
Currently I've found two possible solutions to this problem:
-
Publishing the metadata in a second collection and join them on the client, as
percolate:find-from-publicationdoes it. While the idea is good and the approach is very clean, it can be very slow on your client. -
Adding a custom field to the document when publishing, as
peerlibrary:subscription-scopedoes it. This plugin seems like having a very neat and effective approach, but doesn't work withreywood:publish-composite.
In my opinion, Meteor should natively provide a solution for this problem.
I want it now. What can I do?
- Install
reywood:publish-compositeand use it for all your publications. - The options-parameter of your cursor, returned in the publication, you should include a transformator that adds a property, specific for this publication.
- In your collection you should define a transformator that removes this property.
What happens here in detail?
When publishing your documents, Meteor will use the transformator, specified in your cursor, to add this field. When fetching the documents on the client side it will remove this field. The transformation will also take place when fetching documents on the server, but without effect. This might throttle your performance a tiny bit 😜
Why do I need reywood:publish-composite?
You can find an explanation in the issue 28 of their repository or in this post.
Give me an example please.
const Posts = new Mongo.Collection('posts', {
transform: (doc) => {
delete doc._publications_latest_posts;
return doc;
},
});
if (Meteor.isServer) {
Meteor.publishComposite('latest_posts', (selectors, options) => {
const definition = {
find() {
options.transform = (doc) => {
doc._publications_latest_posts = true;
return doc;
};
return Posts.find(selectors, options);
},
};
return definition;
});
}
if (Meteor.isClient) {
Meteor.subscribe('latest_posts', { deleted: false }, { limit: 10 }, { onReady: () => {
// Will only find posts, published by the 'latest_posts' publication.
Posts.find({
_publications_latest_posts: true,
}, {
sort: { createdAt: -1 },
});
} });
}
The only strange thing though: You're querying for a field on the client that you'll never see after you fetched the documents ...
What's the downside of this solution?
As you define a transformator, you can't use other plugins that also want to set it, since only one transformator can be defined for a collection or query. This makes this solution incompatible f.e. with dburles:collection-helpers. Dropping the collection helper will enable this again, but will also return the extra field when you query the collection. If you use dburles:collection-helpers, take a look at this comment on their repository.
but doesn't work with reywood:publish-composite.
It doesn't? Strange. It does work with https://github.com/peerlibrary/meteor-reactive-publish. :-)