I have a meteor app where I want to let the user click buttons to switch between 2 different filtered views of the data, say "chart" records with a status of 10 or 11. Some users of the app might never want to see status 10, while others might never want to see status 11.
I'm trying to find a way through publish/ subscribe to work this out most efficiently... not pulling up records someone doesn't want to see, while also reducing network traffic.
First idea was the following... a publish on the server with a parameter of the status:
Meteor.publish("charts1", function (status) {
console.log('someone subscribed to my publish of charts.. returning all charts now of status ' + status + " max 500 though");
return Chart.find({"chartStatus": status}, {limit: 500, sort: {"demographics.lastName": 1}});
});
then, on client, I have a template helper:
chartsOnClient: function () {
return Chart.find({"chartStatus":Session.get('currentStatusFilter')}, {sort: {"demographics.lastName": 1}});
}
and 2 buttons which, when clicked will set the session filter and subscribe at the same time:
Template.addChartForm.events = {
'click #mybutton10': function () {
console.log("subscribing to to status 10...");
Session.set('currentStatusFilter', 10);
Meteor.subscribe('charts1', 10);
},
'click #mybutton11': function () {
console.log("subscribing to status 11...");
Session.set('currentStatusFilter', 11);
Meteor.subscribe('charts1', 11);
},
}
and, of course, a template that iterated over "chartsOnClient" to display the records.
This worked... when I clicked button10, I got status 10 in my template, and clicking button11 gave me status 11 in my template...And, the added benefit was that if I never clicked button11, my local client only held the records of status 10, and vice versa, and clicking both buttons would fill up my local collection with the union of both sets.
The only issue I see with this method is that every click of the buttons results in the server message "someone subscribed to my publish of charts..."... indicating that the client is talking to the server and running the find method.
I suspect this is not ideal... for, if I wanted, I could move the 2 "subscribe" calls outside of the click events, like this:
Meteor.subscribe('charts1', 10);
Meteor.subscribe('charts1', 11);
Template.addChartForm.events = {
'click #mybutton10': function () {
console.log("subscribing to to status 10...");
Session.set('currentStatusFilter', 10);
},
'click #mybutton11': function () {
console.log("subscribing to status 11...");
Session.set('currentStatusFilter', 11);
},
}
and when I do this, I get the same end user experience, however, the server console only shows the "someone subscribed to my publish"... message once upon startup, instead of every time the buttons are clicked.
The downside is that both sets of records are pulled up to the client for each user, even users that might never click on both buttons. But the upside is that the subscribe method is not called each time they click to switch between views of the data...
Is there something I'm not understanding here? Which method is best? is there a better way to do this altogether? I'm new to meteor and mongo.
Thank you.
Edit, based on @mattk , I am going to do the subscribes in the button clicks, but use an array in a session variable to prevent a second subscription if I've already subscribed with that particular filter:
'click #mybutton10': function () {
Session.set('currentStatusFilter', 10);
var filtersAppliedSoFar = Session.get('filtersAppliedSoFar');
if (filtersAppliedSoFar.indexOf(10) == -1) {
console.log("subscribing to to status 10...");
filtersAppliedSoFar.push(10);
Session.set('filtersAppliedSoFar', filtersAppliedSoFar);
Meteor.subscribe('charts1', 10);
}
},
'click #mybutton11': function () {
Session.set('currentStatusFilter', 11);
var filtersAppliedSoFar = Session.get('filtersAppliedSoFar');
if (filtersAppliedSoFar.indexOf(11) == -1) {
console.log("subscribing to status 11...");
filtersAppliedSoFar.push(11);
Session.set('filtersAppliedSoFar', filtersAppliedSoFar);
Meteor.subscribe('charts1', 11);
}
},
This way, I don't pull up the data until the user clicks on the particular filter, but I also don't resubscribe if they click back and forth between the 2 filters, which is expected.
EDIT AGAIN: after asking this question How do you securely log out and clear all subscriptions? and getting directed toward Subscription Manager https://github.com/meteorhacks/subs-manager I have discovered that Subscription manager achieves what I was looking for here: I didn't want it to hit the server a second time if my client called .subscribe again. Instead of using a session variable (filtersAppliedSoFar) to know if the client has already subscribed, the subs manager keeps track of this automatically...I just call .subscribe on the subscription manager object and it won't hit the server the second time. .. then the added benefit is I can call .clear() when logging out and all subscriptions are stopped.
There's nothing wrong with your first pattern. Every time you talk to the server, you want to ask it or tell it something new, and that's exactly what you're doing: you're asking it for ONLY the data you need. If you want to reduce bandwidth, limit the fields returned; chances are you aren't going to need every field that is stored in the doc.
I follow something like this:
//Client code (event click)
Meteor.subscribe('patients',
{"chartStatus":Session.get('currentStatusFilter')},
{
fields: {'demographics': 1, 'chartStatus': 1},
sort: {"demographics.lastName": 1}
});
//Server code
Meteor.publish('patients', function(query, options) {
if (options) {
check(options, {
sort: Match.Optional(Object),
limit: Match.Optional(Number),
fields: Match.Optional(Object)
});
}
return Patients.find(query,options);
});
Note that the client can now ask for whatever fields she wants. If in the future there are certain fields in the doc that shouldn't be sent over the wire, you need to do a permission check, too. Right now, this doesn't seem like a problem for you since you've been sending over the entire doc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With