Reputation: 2323
I'm using some form inputs to create a new Student
with the following code:
var student_id = Students.insert({firstname: firstInput, lastname: lastInput, price: priceInput});
Meteor.users.update({_id: Meteor.userId()}, {$push: {'student_ids': student_id}});
I have the following subscriptions and publications set up:
// On the client.
Meteor.subscribe('currentUser');
// On the server.
// I know this is ugly, but I need to do quite a bit of joining.
Meteor.publish('currentUser', function() {
if (!this.userId) return;
var userCursor = Meteor.users.find({_id: this.userId}, { fields: {firstname: true, lastname: true, student_id: true, student_ids: true, payment_ids: true, phones: true }});
var user = userCursor.fetch()[0];
if (user.student_ids || user.payment_ids) {
var student_ids = user.student_ids || [];
var studentCursor = Students.find({_id: {$in: student_ids}});
var payment_ids = user.customer.payment_ids || [];
var paymentCursor = Payments.find({_id: {$in: payment_ids}});
var lesson_ids = [];
var expense_ids = [];
studentCursor.forEach(function(doc) {
lesson_ids.concat(doc.lesson_ids);
expense_ids.concat(doc.expense_ids);
});
var lessonCursor = Lessons.find({_id: {$in: lesson_ids}});
var expenseCursor = Expenses.find({_id: {$in: expense_ids}});
return [userCursor, studentCursor, lessonCursor, expenseCursor, paymentCursor];
}
else return userCursor;
});
The problem is that one of my {{#each}}
blocks is listing all of these students, and it works fine, except that it doesn't show the new student until the page is refreshed/restarted etc. The publish/subscribe pair isn't being reactive.
I'm not sure how to elegantly solve this problem. I definitely would prefer not to mess with added
and other such callbacks in the publish function. It seems my collections should handle this behavior on their own.
Thanks in advance!
I changed my publish to use publish-with-relations
, a reactive join package, and it now looks like this:
Meteor.publish('currentUser', function() {
var studentMappings = [{
key: 'lesson_ids',
collection: Lessons,
},{
key: 'expense_ids',
collection: Expenses,
}];
return Meteor.publishWithRelations({
handle: this,
collection: Meteor.users,
filter: this.userId,
options: { fields: {firstname: true, lastname: true, student_id: true, student_ids: true, payment_ids: true, phones: true }},
mappings: [{
key: 'student_id',
collection: Students,
mappings: studentMappings
},{
key: 'student_ids',
collection: Students,
mappings: studentMappings
},{
key: 'payment_ids',
collection: Payments,
}]
});
});
Everything gets published, but it still isn't reactive! When the page is freshly reloaded, everything is there as expected, but immediately after adding a new student, there is only a flicker where that student would be (I suspect this is latency compensation at work).
When I query Meteor.user()
in the console, the student_ids
array is correct:
student_ids: Array[1]
0: "5dafpCD7XGcBnyjWd"
length: 1
and when I meteor mongo
this:
meteor:PRIMARY> db.students.find()
{ "firstname" : "Sterling", "lastname" : "Archer", "price" : "22.50", "_id" : "5dafpCD7XGcBnyjWd" }
everything is also correct, but still the document doesn't show up until a page refresh.
Wasn't publish-with-relations
supposed to solve this problem?
Upvotes: 1
Views: 232
Reputation: 64312
Publish functions are not reactive. Even if the user document changes, the publish will not rerun and send the student documents to the client. What you need is a reactive join. See this answer for a practical solution, and this post for further enlightenment.
Based on the comments below, here is a suggestion for how to trigger a publication based on changes to the user. Note that you don't actually have to do anything with student_ids
in the publish function - it's there just to trigger subscription on a change to that key.
Tracker.autorun(function() {
if (Meteor.user()) {
Meteor.subscribe('students', Meteor.user().student_ids);
}
});
Upvotes: 2