-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cursor values get emptied when passed to Counts.publish() #58
Comments
publish-counts optimizes the field specifier in a cursor to only pull those fields it needs. With a basic count, as used in your example, the field specifier is replaced by At the time this seemed like the proper course of action with the documentation using separate cursors in the examples for publish-counts and Will update the package to keep existing field specifiers on basic counts. @tmeasday originally asked for this behavior when I rewrote the optimizer until I talked him out of it. |
helping to think this through and make sure I'm not requesting a change with bad side effects... For the moment my workaround does at least do the job, even if a touch more slowly, but if you do make this change I'll be interested to try it out and let you know how it's going. When only doing the count I'm not sure if there's any performance hit to having all of those field selectors in there, but if you chose to making it as an option then you'd be able to pick which you wanted to use... though, I guess that option is already built in because user could just provide an empty field selectors parameter or just |
@Diginized, if you're adding a Without a separate cursor for The fix for this issue will behave as follows:
|
OK, I'm cool with doing the two cursor thing and it seems to make sense, but I don't think the behavior I'm getting matches the reason you're citing. Note the "30" displayed in the two screenshots below (code following screenshots) What's interesting, and surprised me initially, is that when I use the same cursor for both, the method that results in the blank records coming back, it still returns exactly 30 blanks... so Just so that I'm not confusing anything, here are some screenshots (with code included) to go with what I'm saying.
What's weird to me is that this is how the client is coming up with that "30" count: Template:
Helper:
Is this the expected? Am I making sense? |
Yea, I'm not writing very cogent comments. publish-counts does not drop According to #21, Meteor is a bit inconsistent on how If you only need the initial count without subsequent reactive updates, then your use of one cursor appears to be sufficient. I just need to leave your field specifier alone. You should disable reactive counts in this case. Yes, this apparently is expected, and you're making better sense than I have been. The screenshots help very much. Thank you for including those. I also didn't realize that your earlier comments mentioned one cursor is loading faster than two. Out of curiosity, does using the noReady option with two cursors affect the load time? |
@boxofrox I'm not completely following but don't you think the answer here is that we should just clone the cursor before we start messing with it? I've done something like this before, the code looks something like:
(The code above works both client and server, and respects transform, neither of which we need) |
@tmeasday Perhaps. I'm not entirely sold on cloning.
Meteor.publish('posts-visits-count', function() {
Counts.publish(this, 'posts-visits', Posts.find(), { countFromField: 'visits' });
});
My cloning ability in javascript is weak. I'm not certain of the problems/pitfalls I will run into attempting it. Your example is a good point to start from. My opposition to cloning is I don't understand it enough to address these questions. I'll give it a shot and see what I find. Thanks for jumping in here. :) |
|
With respect to (3), yes it's a bug. My intended fix is to modify the field optimizer to leave any field specifier from the user alone, otherwise set an undefined field specifier to This was the behavior you asked for when I rewrote the optimizer, but I argued there was no reason to keep the user's field specifier for basic counts. I thought standard operating procedure for publish-counts was |
@boxofrox, to be honest, I originally assumed the same as you about giving Based on my 3 min little test right now, @tmeasday's suggestion in #59 for wrapping it in Meteor.defer() is working out pretty well regardless of whether I'm using a shared or unique cursor. The first page of results are now appearing before the total count, which from a UX perspective is much closer to that "snappy" goal I'm trying to achieve.
I will try messing around with some of the other suggestions listed above and report back if I learn anything potentially useful, but it will probably be a couple of days before I can get to it. |
The PR for #57 is up, so I will be looking into this next. After some deliberation, if we move forward with cloning cursors, I'm of the opinion it should be an opt-in feature. This can be provided via a
Optimizing the field specifier will still be a separate problem. As #53 points out, Collections middleware may modify the field specifier in addition to the user's fields. At this point publish-counts is unable to distinguish which fields are unecessary (user) or necessary (middleware). Thus, cloning won't be an opportunity to modify the field specifier. On a side note, the need for optmizing assumes that reducing the quantity of fields returned from a query improves performance. I have not read about or tested this. IMO, if a cursor is shared between |
@boxofrox - Thanks for all your diligence here. Let's discuss this question a little more perhaps. I think there's realistically two main ways to use
Now, on the question of performance, I've not tested it closely, but it seems clear that in network bandwidth alone it's going to be better to not fetch the full document but just the There'd be an argument if it was possible we could share the observer with the second use of the cursor, but this is certainly not going to be the case. If we were publishing the full document set, there'd be no point in publishing the count. So it's fair to assume that the user is not publishing the entire cursor. |
@tmeasday I thought about this over the week, but didn't think up any counter examples, so I concur with your assessment. Though I'm still a bit hazy on the implications. Here's where I'm at.
I think the rest of my preceding comment still stands. If we automatically clone the cursor in With the With cloning, I think optimization should always occur, because we cannot guarantee that a cursor will have defined On a side note. Another issue I have with cloning cursors is that cursors are inconsistent between local collections |
Glad we are getting closer to the bottom of this @boxofrox. I'm still a little confused about the "collection middleware" (I'll admit I'm not totally up to speed with what that is). Can we nail down a simple example of what we are talking about here? (I'm trying to follow the comments above but not quite seeing it). On the final point, I think a simple |
Certainly. In #53, kristijanhusak used a package called meteor-partitioner. It wraps around a // quick hacky example. likely broken. based on examples on paritioner's github page.
var ChatMessages = new Mongo.Collection('messages');
Partitioner.partitionCollection(ChatMessages); // Adds hooks to a particular collection
// so that it supports partition operations.
if (Meteor.isServer) {
Meteor.publish('messages', function () {
var cursor = ChatMessages.find();
// partitioner added a _groupId field specifier to this cursor.
Counts.publish(this, 'message-count', cursor);
// Counts.publish just optimized the field specifier list to { _id: true }.
// No more partitioning.
return ChatMessages.find();
});
} I started referring to packages like Partitioner as Collection middleware, since it technically adds a layer between a |
Btw, @tmeasday. You mention an isomorphic API for three types. Which three types are you referring to? |
Oh, I was referring to server collections, client (i.e. server backed) collections, and local collections (i.e. |
Thanks @boxofrox. My reading of https://github.com/mizzao/meteor-partitioner/blob/master/grouping.coffee#L139 is that it's adding Obviously we don't care if the |
Ok, I completely misunderstood how Partitioner was working. I'm surprised any of my solutions to kristijanhusak worked in this case, because I was trying to let him add Well, this is good news. Since, Partitioner is completely transparent, I'm okay moving forward under the assumption that similar libraries should also be transparent. |
man I just spent a whole day trying to figure out why the hell my publish wasn't working properly... and it was because of this issue. how annoying. |
also helps understand percolatestudio#58
I thought this problem was resolved though? @KristerV I'm pretty sure you don't need to do what you did in that documentation example. Sharing the cursor is a thing that we do all the time. |
really? uhhh.... still had this issue like yesterday. i'll try again tomorrow |
I haven't had much time to get the cursor cloning working and tested to my satisfaction. This is still a pending issue. |
I'm not sure why, but when I save my search cursor to a variable (so that I can use it twice) and pass it into Counts.publish() and then use it again to return the values to the client, the cursor sent to the client has _id fields only. As you can see in the code below, the search specifies which fields are to be returned to the client, and this works just fine if the Cursor.publish() line is commented out. But with that line active the fields{} parameter seems to be overridden.
I did find a workaround (below in case it benefits others) but the workaround is a little less elegant and I wanted to ask if I was doing something wrong.
Is this the best way to do it?
Workaround: Instead of using
cursor
in the Counts.publish() function, I just do a new Contacts.find and bring down the same searchParameters variable that I was already doing above. This method requires that I save all of my search parameters into a separate object to avoid duplication (DRY).Thanks in advance, and thanks for this handy package !
The text was updated successfully, but these errors were encountered: