Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you conditionally send data to the client in Meteor?

I'm trying to figure out how to conditionally send data to the client in meteor. I have two user types, and depending on the type of user, their interfaces on the client (and thus the data they require is different).

Lets say users are of type counselor or student. Every user document has something like role: 'counselor' or role: 'student'.

Students have student specific information like sessionsRemaining and counselor, and counselors have things like pricePerSession, etc.

How would I make sure that Meteor.user() on the client side has the information I need, and none extra? If I'm logged in as a student, Meteor.user() should include sessionsRemaining and counselor, but not if I'm logged in as a counselor. I think what I may be searching for is conditional publications and subscriptions in meteor terms.

like image 384
Diogenes Avatar asked Dec 28 '12 19:12

Diogenes


2 Answers

Use the fields option to only return the fields you want from a Mongo query.

Meteor.publish("extraUserData", function () {
  var user = Meteor.users.findOne(this.userId);
  var fields;

  if (user && user.role === 'counselor')
    fields = {pricePerSession: 1};
  else if (user && user.role === 'student')
    fields = {counselor: 1, sessionsRemaining: 1};

  // even though we want one object, use `find` to return a *cursor*
  return Meteor.users.find({_id: this.userId}, {fields: fields});
});

And then on the client just call

Meteor.subscribe('extraUserData');

Subscriptions can overlap in Meteor. So what's neat about this approach is that the publish function that ships extra fields to the client works alongside Meteor's behind-the-scenes publish function that sends basic fields, like the user's email address and profile. On the client, the document in the Meteor.users collection will be the union of the two sets of fields.

like image 106
debergalis Avatar answered Oct 24 '22 10:10

debergalis


Meteor users by default are only published with their basic information, so you'll have to add these fields manually to the client by using Meteor.publish. Thankfully, the Meteor docs on publish have an example that shows you how to do this:

// server: publish the rooms collection, minus secret info.
Meteor.publish("rooms", function () {
  return Rooms.find({}, {fields: {secretInfo: 0}});
});

// ... and publish secret info for rooms where the logged-in user
// is an admin. If the client subscribes to both streams, the records
// are merged together into the same documents in the Rooms collection.
Meteor.publish("adminSecretInfo", function () {
  return Rooms.find({admin: this.userId}, {fields: {secretInfo: 1}});
});

Basically you want to publish a channel that returns certain information to the client when a condition is met, and other info when it isn't. Then you subscribe to that channel on the client.

In your case, you probably want something like this in the server:

Meteor.publish("studentInfo", function() {
  var user = Meteor.users.findOne(this.userId);

  if (user && user.type === "student")
    return Users.find({_id: this.userId}, {fields: {sessionsRemaining: 1, counselor: 1}});
  else if (user && user.type === "counselor")
    return Users.find({_id: this.userId}, {fields: {pricePerSession: 1}});
});

and then subscribe on the client:

Meteor.subscribe("studentInfo");
like image 40
Rahul Avatar answered Oct 24 '22 08:10

Rahul