简体   繁体   中英

Mongoose - Populate object in object

Assuming that I have 3 models :

// Parent
const ParentSchema = new Schema({
    child: {
        type: ObjectId,
        ref: 'Child'
    },

    ...
});

// Child
const ChildSchema = new Schema({
    subChild: {
        type: ObjectId,
        ref: 'SubChild'
    },

    ...
});

// SubChild
const SubChildSchema = new Schema({
    name: String,
    ...
});

I'm using findOne on Parent , and I'd like to use populate on Child , but also on SubChild :

Parent.findOne(options)
    .populate('child', 'subChild')
    // Trying to add another populate on subChild property like : .populate('<above_subChild>', 'name')
    .select('child')
    .exec(function (err, parent) {
        callback(err, parent.toJSON());
    })
;

Is there a way to do that with populate ?


Currently, parent.toJSON() returns :

{
    // Parent _id
    _id: XXX,
    child: {
        _id: XXX,
        subChild: <subChild_ObjectID>        
    }
}

And below is the result I'd like to have by adding another populate on subChild property is :

{
    // Parent _id
    _id: XXX,
    child: {
        _id: XXX,
        subChild: {
            _id: XXX,
            name: XXX
        }
    }
}

This also will work :

Parent.findOne(options)
  .select('child')
  .populate('child.subChild')
  .exec(function(err, parent) {
    callback(err, parent.toJSON());
  });

Referring to the documentation for populate , the query would need to be structured as follows for populating multiple levels:

Parent.findOne(options)
  .populate({
    path: 'child',
    populate: {
      path: 'subChild'
    }
  })
  .select('child')
  .exec(function(err, parent) {
    callback(err, parent.toJSON());
  });

One thing to note with using mongoose's populate method is that every population requires a separate query. So in this case, while the implementation uses one explicit findOne method, mongoose is actually executing three queries serially.

This would be roughly equivalent to (slightly pseudo-coding):

Parent.findOne().exec().then((parent) => ([
  parent,
  Child.findById(parent.child).exec()
])).then(([parent, child]) => ([
  parent,
  child,
  SubChild.findById(child.subChild).exec()
])).then(([parent, child, subChild]) => {
  child.subChild = subChild;
  parent.child = child;

  return parent;
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM