34

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?

HGandhi
  • 1,586
  • 2
  • 14
  • 27
  • 1
    Been here once, answer were unclear to me. Then I stumbled upon an answer that clarifies relations between collections, publish, subscribe, etc. http://stackoverflow.com/a/21853298/1429390 Then the answers here were clearer. – Stéphane Gourichon Mar 17 '17 at 16:37

3 Answers3

48

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.

WispyCloud
  • 4,140
  • 1
  • 28
  • 31
  • 1
    You know I just tried this five minutes ago and it didn't work which is why I asked this question. I tried it again and suddenly it does work. Upvotes for you! – HGandhi Oct 31 '12 at 05:55
  • 2
    Hey, I am trying my client js to `subscribe` that `userData` but I am having a hard time. Maybe because I do not have firm grasp of the meteor concept. How should I set it in the client side? – user482594 Nov 10 '12 at 08:02
33

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.

colllin
  • 9,442
  • 9
  • 49
  • 65
JTE
  • 1,301
  • 12
  • 14
  • 4
    Meteor documentation doesn't mention the subscribes. Thanks for the tip! – agentofuser Jun 08 '13 at 08:19
  • 3
    Meteor docs also don't mention `autosubscribe` one bit. Is that deprecated? – Jonathan Dumaine Oct 14 '13 at 08:48
  • Meteor.autosubscribe was replaced with Meteor.autorun and later with Deps.autorun. I've edited the answer to avoid confusion. – Dan Dascalescu Feb 26 '14 at 12:22
  • I am new to Meteor and I cannot get how should I access the data after the subscription. I publish all of the users form Meteor.users.find() and after I subscribe to it in the client I am not sure how I should access it. I tried again with Meteor.users.find() but I am getting only the current user. – Neli Chakarova Nov 26 '16 at 19:06
5

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.

Community
  • 1
  • 1
jindrichb
  • 96
  • 1
  • 3
  • 1
    The publication on the server side is not reactive, the server will then just publish data according to the value held in this.userId at the publication time. If you get logged in, there is no notification on the server side which will tell it this.userId changed. For this reason, the client should resubscribe once logged in. This is what happen reactively when you specify Meteor.userId() within the Deps.autorun subscription scope, at this time then the server will have the right client's userId under this.userId. – Flavien Volken Nov 19 '14 at 13:10