Fred J.
Fred J.

Reputation: 6039

userId gets into the document magically

This Meteor code is working fine, but I would like to ask if it is the way Meteor does things or it is a un predictable side effect that may change under some condition later.
The things is that when I do
DisplayCol.insert({action: 'task1', element: 'p', value: value_variable});
Meteor also inserts the correct userId (using 2 different browsers logged in as 2 different users) which I did not explicitly included in the document.

The above line of code is inside a server side function which is called from Meteor method.

here is the relevant information;

//lib/collection.js
DisplayCol = new Mongo.Collection('displayCol');

//server.js

Meteor.publish('displayCol', function () {
  return DisplayCol.find({userId: this.userId});
});
DisplayCol.before.insert(function (userId, doc) {
  doc.userId = userId;
});

In the docs of Collection hooks > Additional notes > second bulleted paragraph says:

userId is available to find and findOne queries that were invoked within a publish function.

But this is a collection.insert. So should I explicitly include the userId in the document or let the collection hook do its hidden magic? Thanks

Upvotes: 1

Views: 79

Answers (1)

Kishor
Kishor

Reputation: 2677

No, there is no hidden magic in that code, your before hook is inserting the userId field in the document.

When you do an insert like this,

DisplayCol.insert({action: 'task1', element: 'p', value: value_variable});

the doc that your are inserting is { action: 'task1', element: 'p', value: value_variable }

Because, you have this hook,

DisplayCol.before.insert(function (userId, doc) {
    doc.userId = userId;
});

it changes the doc before inserting into collection. So the above hook will change your doc to {action: 'task1', element: 'p', value: value_variable, userId: 'actual-user-id' }

This is the expected behaviour.

Regarding your other point in the question,

userId is available to find and findOne queries that were invoked within a publish function.

Previously userId parameter in the find and findOne returns null, so user needs to pass userId as a parameter as mentioned in this comment. Additional notes mentions that the hack is not required any more. It has nothing to do with inserting userId field into the collection document.

To have a quick test, remove the DisplayCol.before.insert hook above, you will not see userId field in the newly inserted documents.

UPDATE

Just to clarify your doubt further, from the 4th point in the docs that you provided

It is quite normal for userId to sometimes be unavailable to hook callbacks in some circumstances. For example, if an update is fired from the server with no user context, the server certainly won't be able to provide any particular userId.

which means that if the document is inserted or updated on the server, there will be no user associated with the server, in that case, userId will return null.

Also you can check the source code yourself here. Check the CollectionHooks.getUserId method, it uses Meteor.userId() to get the userId.

CollectionHooks.getUserId = function getUserId() {
  var userId;

  if (Meteor.isClient) {
    Tracker.nonreactive(function () {
      userId = Meteor.userId && Meteor.userId(); // <------- It uses Meteor.userId() to get the current user's id
    });
  }

  if (Meteor.isServer) {
    try {
      // Will throw an error unless within method call.
      // Attempt to recover gracefully by catching:
      userId = Meteor.userId && Meteor.userId(); // <------- It uses Meteor.userId() to get the current user's id 
    } catch (e) {}

    if (!userId) {
      // Get the userId if we are in a publish function.
      userId = publishUserId.get();
    }
  }

  return userId;
};

Upvotes: 2

Related Questions