Wait for data from collection.findOne()

I know there is a simple answer for this but I can’t seem to find it anywhere.

How to make the console log not log undefined:

const user = Meteor.users.findOne(this.userId);
const username = user.username;
console.log(username);

Thanks guys!

While Meteor.userId() is available immediately, Meteor.user() and any other manual data fetching from the users collection takes some time. You have to subscribe to it, and wait for the data to be ready as you would any other subscription. For example:

Meteor.publish('userDetails', function () {
  return Meteor.users.find(this.userId, {
    fields: {
      firstName: 1,
      lastName: 1,
    },
  });
});

To add a bit more insight, a way you could wait for subscriptions to be ready on the client (aside from simply subscribing) is:

Template.myPage.helpers({
    ready: function () {
        return Template.instance().subscriptionsReady();
    }
});

Then in your template:

{{#if ready}}
   <!-- add html here -->
{{else}}
    <p>Loading</p>
{{/if}}

“Ready” will be true once the subscriptions have finished downloading to the client. It will show the Loading text until subscriptions are downloaded, and then once it is “ready” will show the page you want the user to see.

I should have specified this is in a method.

Not necessarily. You can just subscribe to the userDetails publication in a template/React component on the client side, and get access to what you need. A method shouldn’t be needed.

As @ffxsam said, you can do it through a subscription rather than a method.

If you really need it in a method specifically for some reason, I would be glad to provide more assistance on how you could retrieve the name, but it is hard to give that guidance without knowing what the method is actually doing.

To further specify, I am using this code in an insert method where I need the username in a the documents of a different collection.
So my issue here is waiting for the data to be in the const user so I can access it in the rest of the code.

Thoughts?

This should work as expected in a server-side method (i.e. not a client stub/simulation). I wonder if you’ve used ES2015 syntax for your method:

Meteor.methods({
  myMethod() { // or myMethod: () => {
    const user = Meteor.users.findOne(this.userId);
    const username = user.username;
    console.log(username);
  }, ...

Using that form does not give you the correct this (one which includes this.userId) - you must currently use ES5 syntax for methods (and publications):

Meteor.methods({
  myMethod: function() {
    const user = Meteor.users.findOne(this.userId);
    const username = user.username;
    console.log(username);
  }, ...