Is there any use case to subscribe more than once to the same publication?


#1

I’m trying to understand the code a freelancer wrote for me on the client (still learning frontend). Is there any possible use case you can think of that makes it necessary to subscribe more than once to a given publication?

I don’t mean having several different publications on the same collection (to handle subsets of data), I mean having a subscribe to the same publication at two different places in the client code (in the navbar and on connection to the remote server).

EDIT: in one instance a Session variable is used as the parameter (the publish requires one param as a filter) and in the other instance a local variable is used (again as the required parameter).

Thanks!


#2

It depends on your subscription, route or template level.

If template level, you can subscribe more than once on a publication per template.

just wrap it on onCreated like this:

Template.template1.onCreated( function () {
  this.subscribe( 'myPublication' );
} );

Template.template2.onCreated( function () {
  this.subscribe( 'myPublication' );
} );

If route you can subscribe to the current route with multiple template in it but I suggest you go for the template level as this is much maintainable and easy to debug.


#3

Thanks @ajaxsoap for your example. Yes, I’ve read that subscribe in the template is the preferred one over the route (I think this was the earlier way of subscribing).

I assume that there is no downside to such multiple subscription to one publication like in your example? Will Meteor automatically inform all (the same) subscriptions when the data changes or will it just inform the last subscribe only?

It’s indeed twice in onCreated events for templates and once in the initialLoading function after client and remote server are connected (again).


#4

The problem with registering multiple times is that the data is mixed up, which is not always what you’d expect. But there’s a package to workaround this: https://atmospherejs.com/percolate/find-from-publication

To your original question: Yes, it is quite normal to subscribe to a collection more than one time, especially if you’re using template-level subscriptions. This even works if the templates are rendered at the same time. If the templates are rendered subsequently (to show different pages in your app), Meteor will automatically drop the subscriptions onDestroy() and re-subscribe in the other template. This will cause additional network traffic. You can lower this traffic by using Arunoda’s SubsManager: https://atmospherejs.com/meteorhacks/subs-manager

You were also asking for use-cases where it makes sense to multi-subscribe at the same time. One sample use-case I had was to show in two boxes a) the most recent posts and b) the most popular posts of a social network. But in this case, you’d run into the problem I mentioned above, that both data sets will be mixed up, so you have to sort them out using find-from-publication. Or, as I did, you could just use methods for this, if it shouldn’t be reactive. Which is always a good option to lower resource consumption on the server-side.


#5

Thanks @waldgeist. I’ve read through the README of the package but I don’t understand the issue. You seem to indicate that what I’ve asked earlier (not every subscribe then gets the same data) is happening.

Could you explain the problem (“data is mixed up”) a bit more?

As for your comment about the subs-manager - unfortunately I can’t use it as I have two apps, the server data is served via a remote app and subs-manager doesn’t have that functionality (though @arunoda admitted it would be a good functionality to add).


#6

I’ve just added some more explanations above :slight_smile:

With “mixed-up” I mean that all data that you retrieve is mixed in the same collection, so in my example the most recent posts would be mixed up with the latest posts and both boxes would show the same content.


#7

Isn’t that done with a different filter in the .find? So a will be: Posts.find({ userId: Meteor.userId() }, {sort: {created: 1}}) and b will be: Posts.find({ userId: Meteor.userId(), social: facebook }, sort: {views: 1}})

I think I still have problems understanding the use case for this package but I’m pretty sure there is a very valid one. Maybe you can remove “mein Brett vor’m Kopf”) LOL


#8

This is especially useful when you do pagination, where you can’t simply filter unwanted results in the .find(). For example, let’s say you want to show 3rd page of users with best game result. You subscribe to your collection, get the data, show it on the screen and… surprise, there’s a currently logged in user among the data, because he’s in the database by default.


#9

Ok, I think I finally get it. The other subscription would destroy the pagination of the first subscribe in @waldgeist example, is that correct?

If pagination is a possible problem for this “mixed-data” by multiple subscribes to the same publication then I have to be careful as well. So in the case when pagination is used, it’s best to only have one subscription or if it’s needed in two templates then use the package from percolate. Right?

To be more concrete, in my project the subscribe is in the code that is executed as soon as the client connects (or I assume it’s executed as well when it re-connects after a drop) and in (minimum) one template.

From what I do understand so far (like I said, still learning every day), it wouldn’t be necessary to do a subscribe in the connect/reconnect code when the same subscription is already in one template executed by the onCreated event. Or am I wrong and a reconnect would lose the subscription and hence no data would be received in the template (as it’s only executed when it’s created).

I slowly start to think only the right doses of alcohol will help me fully understand this pub/sub thing (and your answers obviously) LOL


#10

Pagination is one problem. Other problems are network consumption and (probably) security.

Using filters on the client side requires you to include the filterable fields in all documents sent to the server. Which increases the amount of data transfered over the wire, which I am trying to avoid, since my app is running on mobile devices. It could also be that those fields contain confidential information which the client shouldn’t be able to see (remember: you can use the browser console to inspect data or call Meteor directly). Might not be the case in the samples I’ve given, but I had such cases.


#11

AFAIK, losing the connection does not invalidate data that has already been sent to the client. Once the client reconnects, it will get the latest published data and only this amount is being transfered.


#12

Thanks, you guys really rock. Learned a lot from this thread. I will try to see what effect I get when I comment out the subscribe code in the connect/reconnect section.

I’m restricting the amount of fields as much as I can in some queries but I haven’t looked at all queries (lazy to check and write the fields statement) - that would positively affect the I/O times from Mini-Mongo. I also have to check the publications side again to transfer the absolute minimum necessary, great tip!


#13

Just to clarify one thing. If the author of this project you inherited is doing subscriptions to the same publication with the same arguments or with no arguments, then he’s obviously doing an unnecessary thing. Multiple subscriptions make sense only when you use different arguments.


#14

Sorry for double posting, but this is rather important:

percolate:find-from-publication package gathers the following data:

{
  _id: 'a-unique-id-for-this-record',
  collectionName: 'posts',
  documentId: 'the-real-document-id',
  publicationName: 'allPosts',
  rank: 7 // a globally increasing rank over all publications.
}

So I’m not that sure that it can actually differ between multiple subscriptions to the same publication - only to multiple publications of the same collection. This way it wouldn’t be able to help in this particular use case.


#15

I know this is an older topic, but damn is this a nightmare what you describe!

Try working with this when dealing with ionic 2.

The problem is you want to try to keep your network resources down. So you’ll do a sub on a collection and just pull certain fields. Depending on where your user navigates to, you may not need anymore data out of the collection. On that first page, you still need it to be reactive for changes later that will effect that earlier page. So, you try and do a sub again with new criteria; again to keep the network resources down. Then you go within another page that the previous page depended on reactive content. Try to do an update and go back to previous page with that subscription and everything will go to hell on you.

I had run into this problem earlier in my testing, but honestly I didn’t really know what was going on. That’s when I figured out I didn’t need to re-subscribe, but I was pulling a fairly small collection. I would just load the whole thing. The debug info is not very good of what is happening. So you don’t realize there is basically a collision or somehow your data is getting nuked.

When I initially started using Meteor, my impression was that it would pull data as needed and merge with your current minimongo on the client side. This assumption was VERY wrong.

I had already started using methods to run certain queries, that didn’t need to be reactive. So I’m very familiar with that. The deal is, if you start doing stuff like that it is almost best just to roll your own. It would cut down on a lot of the bloat from Meteor.

Don’t get me wrong, Meteor is awesome in a lot of ways. But it has some harsh shortcomings. I am going to check out the package you suggested and see if I can work around the issues I’m running into.

Thanks for the suggestion!