In my server folder I have a file where i'm doing the following
Meteor.publish("all_jobs", function(jobs) {
return Jobs.find();
});
Meteor.publish("user_jobs", function(user_id) {
return Jobs.find({userid: user_id}, {sort: {date: -1}});
});
On the user his blogpost page I do the following:
Session.set("userid", Meteor.userId());
Meteor.subscribe("user_jobs", Session.get("userid"));
Template.userJobs.helpers({
jobs: function(){
return Jobs.find();
}
});
On my homepage I would need all the blogpost. So i'm trying to access Meteor.subscribe("all_jobs");
The problem i'm having right now is that all the posts are showing up on my user profile instead of only the posts published by the user.
Any suggestions?
Thanks
When you make multiple subscriptions for the same collection, the results will be merged on the client. After subscribing to all_jobs, the client will now have all of the jobs in its local database until the subscription is stopped. When you go to find some of the jobs in the userJobs template, you will need to indicate which ones you actually are interested in. Modify your helper as follows:
Template.userJobs.helpers({
jobs: function() {
return Jobs.find(userid: Meteor.userId());
}
});
Found the problem. The problem was I was subscribed to all the publications because I just subscribed somewhere random in my code.
I fixed this by adding a waitOn in my route:
waitOn: function() {
return [
Meteor.subscribe("userJobs"),
];
},
Related
In Meteor, one can add additional fields to the root-level of the new user document like so:
// See: https://guide.meteor.com/accounts.html#adding-fields-on-registration
Accounts.onCreateUser((options, user) =>
// Add custom field to user document...
user.customField = "custom data";
return user;
});
On the client, one can retrieve some data about the current user like so:
// { _id: "...", emails: [...] }
Meteor.user()
By default, the customField does not exist on the returned user. How can one retrieve that additional field via the Meteor.user() call such that we get { _id: "...", emails: [...], customField: "..." }? At present, the documentation on publishing custom data appears to suggest publishing an additional collection. This is undesired for reasons of overhead in code and traffic. Can one override the default fields for Meteor.user() calls to provide additional fields?
You have a couple of solutions that you can use to solve this.
Null Publication
Meteor.publish(null, function () {
if (this.userId !== null) {
return Meteor.users.find({ _id: this.userId }, { fields: { customField: 1 } });
} else {
return this.ready();
}
}, { is_auto: true });
This will give you the desired result but will also result in an additional database lookup.. While this is don't by _id and is extremely efficient, I still find this to be an unnecessary overhead.
2.Updating the fields the Meteor publishes for the user by default.
Accounts._defaultPublishFields.projection = { customField: 1, ...Accounts._defaultPublishFields.projection };
This has to be ran outside of any Meteor.startup blocks. If ran within one, this will not work. This method will not result in extra calls to your database and is my preferred method of accomplishing this.
You are actually misunderstanding the documentation. It is not suggesting to populate and publish a separate collection, just a separate publication. That's different. You can have multiple publications/subscriptions that all feed the same collection. So all you need to do is:
Server:
Meteor.publish('my-custom-user-data', function() {
return Meteor.users.find(this.userId, {fields: {customField: 1}});
});
Client:
Meteor.subscribe('my-custom-user-data');
I want to have client-side access for a certain set of fields for ALL users while I would like to have access to even more fields for the current user only. How do I go about writing publish code to accomplish this?
Right from Meteor documentation:
Meteor.publish("userData", function () {
return Meteor.users.find({_id: this.userId},
{fields: {'other': 1, 'things': 1}});
});
And also:
Meteor.publish("allUserData", function () {
return Meteor.users.find({}, {fields: {'nested.things': 1}});
});
Hope this helps.
As mentioned above, the
Meteor.publish("userData", function () {
return Meteor.users.find({_id: this.userId},
{fields: {'other': 1, 'things': 1}});
});
and
Meteor.publish("allUserData", function () {
return Meteor.users.find({}, {fields: {'nested.things': 1}});
});
publish functions will push the data from the Users collection.
Subscribe with
Tracker.autorun(function () {
Meteor.subscribe("userData");
Meteor.subscribe("allUserData");
});
And the additional data will automatically go into the Users collection and be available in the Meteor.user() object.
My story with that:
I proceeded as documentation says, but encountered with weird behavior.
I had publish function, where I published whole profile and email object for current user (lets say userData) and just some subset for the other users (allUserData).
When I had -
Meteor.subscribe("allUserData");
Meteor.subscribe("userData");
On client side right after user logged in, I've received just allUserData data. Thats mean even for my logged in user (That user couldn't see his own email address). When I refresh browser, bug was fixed and I got properly allUserData for all users except one logged in, which has his proper userData (with mentioned email address).
What is interesting, if I changed the sequence of that subscriptions, bug was fixed.:
Meteor.subscribe("userData");
Meteor.subscribe("allUserData");
Putting into Meteor.autosubscribe(function () { }) doesn't changed anything.
Finally I tried put that subscription into Deps.autorun(function() { }) and explicitly add reactivity and the problem with sequence was resolved..:
Deps.autorun(function() {
Meteor.subscribe("allUserData", Meteor.userId());
Meteor.subscribe("userData", Meteor.userId());
// or
// Meteor.subscribe("userData", Meteor.userId());
// Meteor.subscribe("allUserData", Meteor.userId());
});
In publish function I just replace this.userId with userId from parameter.
With next bug which I encountered was, that I've got secret systemData object in profile user's object and that can see just admins, not regular logged in users. But although correct set publish function with 'profile.systemData': 0 that secret object could see all logged in users which looked into his profile object.
Probably it was because my publish function(s) somehow interfered with publish function in Meteor Account package:
// Publish the current user's record to the client.
Meteor.publish(null, function() {
if (this.userId) {
return Meteor.users.find(
{_id: this.userId},
{fields: {profile: 1, username: 1, emails: 1}});
} else {
return null;
}
}, /*suppress autopublish warning*/{is_auto: true});
Anyway I resolved it with help of method Account.onCreateUser() and adding systemData next to profile object, not into profile.
There starts my other problems :) see Meteor.loginWithPassword callback doesn't provide custom object in User accounts doc
PS: If I knew it at begin, I've put systemData object into special collection.
I'm using Iron Router. I have a RouterController that looks something like this:
var loggedInUserController = RouteController.extend({
layoutTemplate: "GenericLayout",
waitOn: function () {
return Meteor.subscribe("TheDataINeed");
}
});
And I have a route defined which uses this controller to wait for the 'TheDataINeed':
Router.route("/myapp", {
name: "Landing",
controller: loggedInUserController,
data: function () {
if(this.ready()){
return {content: "page-landing"};
}
}
});
Now, the problem is the data I am subscribed to is conditional: meaning, depending on the user's role, I publish different data, like so:
if (!Roles.userIsInRole(this.userId, 'subscribed') ) {
return [
myData.getElements({}, { fields: { _id: 1, title: 1}, limit: 5 })
];
} else {
return [
myData.getElements({}, { fields: { _id: 1, title: 1} })
];
}
When the user's role is not 'subscribed', I limit the published data to 5 elements.
The problem is publishing is not reactive, so when the user changes his role for the first time to 'subscribed' and I navigate to my route ("/myapp"), the user still sees the limited number of elements instead of all of them.
Is there a way to manually re-trigger the subscription when I am loading this route? If possible, I'd like to do this without adding new packages to my app.
Not sure about that approach but can you try to set session value in route instead of subscription code. Then in a file on client side where your subscriptions are you can wrap Meteor.subscribe("TheDataINeed") in Tracker.autorun and have a session as a subscription parameter. Every time that session value is changed autorun will rerun subscription and it will return you data based on a new value.
I would to show a list of all users, in my template.
I have:
//publications.js
Meteor.publish('users', function() {
return Meteor.users.find({}, { fields: {username: 1, profile: 1} });
});
//router.js
Router.route('/users/add/:_id?', {name: 'users.add', controller: 'UserAddController'});
UserAddController = RouteController.extend({
subscriptions: function(){
return [ Meteor.subscribe('hospitals'),
Meteor.subscribe('roles'),
Meteor.subscribe('users') ];
},
action: function() {
this.render('addUser', {
data: function(){
return { hospital_id : this.params._id }
}
});
}
});
//client
Template.listUsers.helpers({
users: function() {
return Meteor.users.find({});
}
});
But the list keep showing only the current logged-in user. I have created a list of users using Account.createUser() function What am I doing wrong?
Thanks.
You have to subscribe to a publication using this.subscribe() in subscriptions hook:
// a place to put your subscriptions
subscriptions: function() {
this.subscribe('items');
// add the subscription to the waitlist
this.subscribe('item', this.params._id).wait();
}
Or use waitOn:
// Subscriptions or other things we want to "wait" on. This also
// automatically uses the loading hook. That's the only difference between
// this option and the subscriptions option above.
waitOn: function () {
return Meteor.subscribe('post', this.params._id);
}
By default, Meteor publishes the current user. I see that you have a addUser template and a listUsers template. The problem is that while addUser is subscribed to the users publication, listUsers is not (this would depend on what else you have in your router of course). To fix this, change the call to this.render to render the listUsers template. Then, your users helper should work, and you can render the information however you like.
I tested this with my own app (the Microscope project from DiscoverMeteor) and it worked for me. Hope it works for you too. Comment here if not, and be sure to accept this answer if it worked. =)
I'm using subscriptions manager with iron-router and my problem is this one.
I have a collection "participants" with 2 publications: allParticipants and todayParticipants.
if I go to this page:
Router.map(function () {
this.route('winners', {
waitOn: function () {
return [subs.subscribe('allWinners'),
subs.subscribe('allParticipants')];
console.log("subscribed!");
},
data: function () {
return {
winners: Winners.find(),
participants: Participants.find(),
loginBox: "True"
}
}
});
AllParticipants publication is subscribed and put in cache by the subscription manager package.
If after this, I go to this page:
Router.map(function () {
this.route('participants', {
path: '/',
waitOn: function () {
return subs.subscribe('todayParticipants');
},
data: function () {
return {
participants: Participants.find()
}
}
});
I'm expecting to subscribe only the todayParticipants but as my subscription is automatically named "Participants", It uses the cached subscription from the previous page being allParticipants.
Is there a way to change the name of my subscriptions in order to have each of them in the right cache?
Thanks.
What I do in my waitOn function is first stop my subscriptions like
if (App.subs) {
for (name in App.subs) {
App.subs[name].stop();
}
}
And then I create new subscriptions
App.subs = {
settings: Meteor.subscribe('settings', project),
...
};
return [App.sub.settings, .....];
Hope this helps!
Today, there seems to be no solution to this problem.
More explanation here: https://github.com/meteorhacks/subs-manager/issues/11
What I'm doing now is using a very limited number of subscriptions (filtered mainly on user) and then I create as much data objects as I want filtering my subscriptions in different ways.