Get user name based on user id

My collection stores a userId on each created record.

Cvs = new Mongo.Collection('cvs');
...
    author: {
        type: String,
        autoValue: function(){
            return this.userId
        }
    },

If i do: Created by: {{ cv.author }} i can get the Id of the user who created the object. But what i need is the name.

How can i query the users collection at this point to get the name based on the _id?

can you please post your user collection data?

Iā€™m using the default one from Meteor that uses accounts-ui. Itā€™s not being published anywhere and itā€™s not in any collection.

Use this.user().username or this.user.username instead this.userId.

I donā€™t know how i supposed to use that.
This is how the js looks:

Template.DetaliiInterviu.onCreated(function(){
    var self = this;
    self.autorun(function(){
        var id = FlowRouter.getParam('id');
        self.subscribe('singleCv', id);
    })
});

Template.DetaliiInterviu.helpers({
    cv: () =>{
        var id = FlowRouter.getParam('id');
        return Cvs.findOne({_id: id});
    },
});

I tried adding to the helpers:

    getAuthorName: function(){
        return Meteor.users.find({_id: cv.author});
    },

And in the View:

{{ Created by: {{ getAuthorName }} }}

, but now i get ReferenceError: cv is not defined

I also tried adding the hardcoded string of the user id from the db:

    getAuthorName: function(){
        return Meteor.users.findOne({_id: 'wuAdZkugjY8BsvzoS'});
    },

And now i get output: Created by: [object Object] , which is a progress, but i canā€™t use hardcoded values.

Oh and i just noticed there is no name in the users collection, so i need to look for something else.
There is a ā€œemailsā€ object with ā€œaddressā€ and ā€œverifiedā€ fields.
I guess i need to find a way to display that ā€œaddressā€ field.

I managed to display it using:

Template.DetaliiInterviu.helpers({
    cv: () =>{
        var id = FlowRouter.getParam('id');
        return Cvs.findOne({_id: id});
    },
    getAuthorName: function(){
        return Meteor.users.find({_id: 'wuAdZkugjY8BsvzoS'});
    },
});

    {{#each getAuthorName }}
         {{#each emails}}
             {{address}}
         {{/each }}
     {{/each}}

Now all is left is to replace the hardcoded id with the one cv: () is returning.

Could use it like this
getAuthorName: function(){
return Meteor.users.find({_id: this.userId});
}

Tried it, and when outputing:

                    {{#each getAuthorName }}
                        {{#each emails}}
                            {{address}}
                        {{/each }}
                    {{/each}}

Nothing is showing.

Or if i try simple {{ getAuthorName }} then i get an [object Object], which should be the same object as before and it should be showing the data, but itā€™s not.

I also tried console.log(this.userId); before return and i get undefined twice.

Try this:

Template.DetaliiInterviu.helpers({
  userName: function ( name ) {
    var uName = Meteor.users.findOne( name );
    if ( uName ) {
      return uName && uName.name;
    } else {
      return "No user name";
    }
  }
});
1 Like

I think all posts are thinking the wrong way in this case:

Type in your console:

Meteor.users.find({}).fetch()

In your situation you will get one user only, your own user. That is because standard Meteor only publishes your own user account. Which makes sense, why would you want to send all users to all clients.

So how to fix this issue some basic strategies:

  1. You could publish all users, not very handy and scalable, but it will work. Not to mention not very secure if you publish a bit too much.

  2. Use something as publish composite: https://github.com/englue/meteor-publish-composite/

  3. Denormalize, so when you insert a new document in your collection not only add the id of the user but also the name. Then you can use it in the most simple way. But if a user changes his name you have to update your documents. Not very hard but remember to implement it.

About the name field:

You can signup with username or email. Both will be stored in the user document. Though you may more likely want to just add a name field to the users.

U mean is that freakinā€™ hard or unsafe to get the email of a user who posted a post? :stuck_out_tongue:

And yes i think my biggest problem is that the users collection is not being published and i canā€™t query it.

A workaround would be to also add the email in the database along with the _id when the post is created, but that sux because the email may change in the future, and my field wonā€™t change

Well first: thatā€™s how a document database works itā€™s not a relational one. Read a bit about mongo they have great articles on their website on how to structure your data.

Second: I would not be happy if you share my email with all your website users. Better take a name for it. It will be a very simple thing to harvest all emails if you publish them.

Third: if you want the names to stay up to date you can use a hook: https://github.com/matb33/meteor-collection-hooks on users. Then when a usersā€™ name gets updated your can easily run an update to fix the names.

I guess your template is something like:

{{#each cv }}         
         Author (cv.author)
         {{#each getAuthorName }}
                {{#each emails}}
                        {address}}
                  {{/each }}
          {{/each}}
{{/each}

if so:

 getAuthorName: function(){
    return Meteor.users.find({_id: this.author});
},

because ā€˜thisā€™ would be ā€˜cvā€™ in that helper

@ralof that really doesnā€™t work, that other user is not on the client available. The data is simply not there. It will only work if you are yourself the user. For all other users it will not work.

I understand the privacy thing and how could one harvest it from the console now.
But in my case itā€™s a small internal project, and no one will care. At least for now at my current meteor/jsvascript level.

Would u have an example of how to publish the users emails to make it available for query on the client?

Well, first step is of course to make the user available if you want to display the user infoā€¦

server/publications.js

Meteor.publish(ā€œallUsersā€, function(){
return Meteor.users.find(); //adjust query to return the info you want public
});

client/subs.js

Meteor.subscribe(ā€œallUsersā€)

Would u have an example of how to publish the users email to make it available for query on the client?

Just do something like this (not debugged) on server:

Meteor.publish('allUsers', function() {
  return Meteor.users.find({});
});

And client:

Meteor.subscribe('allUsers');

But like I said: DO NOT DO THIS UNSAFE UNSECURE AND BAD EXAMPLE

So, to give a good example also:

Untested, just to show you the concept with some comments:

Run only on server:

Meteor.users.after.update(function (userId, doc, fieldNames, modifier, options) {
  // Only update when the user is logged in
  if(!userId) {
    return;
  }

  // check to see if the name was changed
  if(modifier.$set && modifier.$set.name && this.previous.name !== modifier.$set.name) {
    // name changed

    // So update your articles which have this users name
    Articles.update({
      // Find them by the userId active
      author.id = userId
    },{
      $set: {
        // and update the name
        'author.name': modifier.$set.name,
      },
    });
  }
});

Now every time the user is logged in and updates his name there will be an update statement on all your articles, your collection, and it will update all names. You donā€™t need to do anything custom for that except this piece.

btw this uses that plugin I mentioned: https://github.com/matb33/meteor-collection-hooks

When you insert a new article you can do this:

Articles.before.insert(function (userId, doc) {
  doc.author.name = Meteor.users.findOne(userId).name;
});

Then you will start directly with the name of the current user so you also donā€™t have to think about that anymore when you create forms to insert the article in the collection.

1 Like