These are chat archives for Automattic/mongoose

29th
Sep 2018
Vladimir Šterjoski
@sterjoski
Sep 29 2018 13:15

Hi, I have a following UserSchema:

const UserSchema = new mongoose.Schema({
  id: {
    type: Number
  },
  firstName: {
    type: String,
  },
  surname: {
    type: String,
  },
  age: {
    type: Number
  },
  gender: {
    type: String
  },
  friends: {
    type: [{ type: Number, ref: 'User' }]
  }
});

An example user would be:

{
    "_id": {
        "$oid": "5baf6e778df8434746850e31"
    },
    "id": 3,
    "firstName": "John",
    "surname": "Doe",
    "age": 42,
    "gender": "male",
    "friends": [
        2,
        4,
        5,
        7
    ]
}

I need to turn all the ids in firends into User objects with corresponding ids. How would I do that? Keep in mind that I'm using id and not _id.

Kev
@lineus
Sep 29 2018 13:19
@sterjoski do you mean you want to convert the existing values already stored in the database from numbers to objectids? or are you asking how to define the type in the schema path so that they are objectids? or both?
Vladimir Šterjoski
@sterjoski
Sep 29 2018 13:23
@lineus I'm working with express and the end goal is to GET /user/:id and return the User (that part is easy just User.find({id: req.params.id})) and on top of that a friendsOfFriend array which contains friends of friends which are not already direct friends with the original user.
If that makes sense. So I'm currently at the friendsOfFriends step and I'm wondering if that could be done using .virtual because I'm using only one model? Or should I achieve it in another way
Kev
@lineus
Sep 29 2018 13:29
@sterjoski Oh, I see. if you only want a set number of levels of indirection you can craft a populate object that specifically goes only so deep, or you can use a plugin, deepPopulate maybe? I'll double check the name.
Vladimir Šterjoski
@sterjoski
Sep 29 2018 13:32
I'll give it a try, thanks.
It's just that most examples use two models, but I only have one so I have trouble figuring things out
Kev
@lineus
Sep 29 2018 13:35
yeah, that's understandable. It really doesn't matter, or at least I've never seen it matter. If your reference is to the same collection or a different one, mongoose will just find the referenced doc from the specified collection like you expect.
Vladimir Šterjoski
@sterjoski
Sep 29 2018 13:50
https://mongoosejs.com/docs/populate.html#deep-populate This wouldn't work for me since I'm not using _id?
Kev
@lineus
Sep 29 2018 13:55
it would, you would just have to create a population object manually with the number of nested populate properties equal to the number of desired levels of indirection. Something like:
User.find({}).populate({ path: 'friends', populate: { path: 'friends', populate: { path: 'friends', populate: { path: 'friends' }}}})
Vladimir Šterjoski
@sterjoski
Sep 29 2018 13:58
I only need two levels.
User.findOne({ id: req.params.id }).populate({ path: 'friends', populate: { path: 'friends' } }).exec((err, user) => {
    console.log(user);
  });
this returns undefined, do I need to changes something in my schema for this to work?
Kev
@lineus
Sep 29 2018 14:02
no, I think you're right, by default it's going to look at the _id path unless you create a virtual. I just ran into a casterror creating an example of this. I'm SLOW on the uptake today :smile:
Vladimir Šterjoski
@sterjoski
Sep 29 2018 14:04
I've tried with this:
UserSchema.virtual('friendsOfFriends', {
  ref: 'User',
  localField: 'id',
  foreignField: 'friends',
  justOne: false
});
Vladimir Šterjoski
@sterjoski
Sep 29 2018 14:13
@lineus thank you. I implemented it in my app and it works.
My original solution was nested User.finds and .forEach... It was a mess so I wanted to switch to populate. Thanks again!
Kev
@lineus
Sep 29 2018 14:27
anytime @sterjoski glad I could help :+1:
Hitesh Joshi
@evoxtorm
Sep 29 2018 18:23
@lineus Thanks, how much time it can take.I mean not an exact figure but any do you have any rough idea???
Kev
@lineus
Sep 29 2018 19:47
@evoxtorm i was playing around with a building 3 field text index this morning on a replicaset running on my localhost, inserting 100K docs took 14 seconds, and building the index took about 9 seconds. Though it's highly dependent on hardware, collection size, the complexity of the index and probably some other stuff that I'm not thinking of :smile: