猫鼬: 深度种群(居住在有人居住的领域)

我有 Category型号:

Category:
...
articles: [{type:ObjectId, ref:'Article'}]

文章模型包含对 Account model的引用。

Article:
...
account: {type:ObjectId, ref:'Account'}

因此,随着填充 articles类模型将是:

{ //category
articles: //this field is populated
[ { account: 52386c14fbb3e9ef28000001, // I want this field to be populated
date: Fri Sep 20 2013 00:00:00 GMT+0400 (MSK),
title: 'Article 1' } ],
title: 'Category 1' }

问题是: 如何填充已填充字段([文章])的子字段(account) :

globals.models.Category
.find
issue : req.params.id
null
sort:
order: 1
.populate("articles") # this populates only article field, article.account is not populated
.exec (err, categories) ->
console.log categories

我知道这里讨论过: 猫鼬: 居住在人口稠密的地区,但是没有找到真正的解决方案

94998 次浏览

Sorry to burst your bubble, but there's not a directly supported solution to this. As for Github issue #601, it looks grim. According to the 3.6 release notes, it looks like the developers acknowledged the issue are happy with manual recursive/deep population.

So from the release notes, the recommended method is to nest populated calls in the callback, so in your exec() function, use categories.populate to further populate before sending a response.

Mongoose has now a new method Model.populate for deep associations:

https://github.com/Automattic/mongoose/issues/1377#issuecomment-15911192

Easiest way to accomplish this in 3.6 is to use Model.populate.

User.findById(user.id).select('-salt -hashedPassword').populate('favorites.things').exec(function(err, user){
if ( err ) return res.json(400, err);


Thing.populate(user.favorites.things, {
path: 'creator'
, select: '-salt -hashedPassword'
}, function(err, things){
if ( err ) return res.json(400, err);


user.favorites.things = things;


res.send(user.favorites);
});
});
globals.models.Category.find()
.where('issue', req.params.id)
.sort('order')
.populate('articles')
.exec(function(err, categories) {


globals.models.Account.populate(categories, 'articles.account', function(err, deepResults){


// deepResult is populated with all three relations
console.log(deepResults[0].articles[0].account);


});
});

The following example is inspired by the question asked @codephobia and populates two levels of many relationships. First fetch a user, populate its array of related orders and include each orderDetail.

user.model.findOne()
.where('email', '***@****.com')
.populate('orders')
.exec(function(err, user) {


orderDetail.model.populate(user, 'orders.orderDetails', function(err, results){


// results -> user.orders[].orderDetails[]
});
});

This works fine in 3.8.8 but should work in 3.6.x.

It might be a bit too late, but I wrote a Mongoose plugin to perform deep population at any arbitrary nested levels. With this plugin registered, you can populate category's articles and accounts with just a single line:

Category.deepPopulate(categories, 'articles.account', cb)

You can also specify populate options to control things like limit, select... for each populated path. Checkout the plugin documentation for more information.

Firstly, update mongoose 3 to 4 & then use the simplest way for deep population in mongoose as shown below:

Suppose you have Blog schema having userId as ref Id & then in User you have some review as ref Id for schema Review. So Basically, you have three schemas:

  1. Blog
  2. User
  3. Review

And, you have to query from blog, which user owns this blog & the user review. So you can query your result as :

BlogModel
.find()
.populate({
path : 'userId',
populate : {
path : 'reviewId'
}
})
.exec(function (err, res) {


})

Populating across multiple levels

Say you have a user schema which keeps track of the user's friends.

var userSchema = new Schema({
name: String,
friends: [{ type: ObjectId, ref: 'User' }]
});

Populate lets you get a list of a user's friends, but what if you also wanted a user's friends of friends? Specify the populate option to tell mongoose to populate the friends array of all the user's friends:

User.findOne({ name: 'Val' }).populate({
path: 'friends',
// Get friends of friends - populate the 'friends' array for every friend
populate: { path: 'friends' }
});

Reference: http://mongoosejs.com/docs/populate.html#deep-populate

This concept is deep Population. Here Calendar,Subscription,User,Apartment are mongoose ODM models in different levels

Calendar.find({}).populate({
path: 'subscription_id',model: 'Subscription',
populate: {path: 'user_id',model: 'User',
populate: {path: 'apartment_id',model: 'Apartment',
populate: {path: 'caterer_nonveg_id',
model: 'Caterer'}}}}).exec(function(err,data){
if(!err){
console.log('data all',data)
}
else{
console.log('err err err',err)
}
});

If you want select multi populate inside populate, you should try this way:

I have Booking schema:

let Booking = new Schema({
...,  // others field of collection
experience: { type: Schema.Types.ObjectId, ref: 'Experience' },
...},{
collection: 'booking'
});

and Experience schema:

let Experience = new Schema({
...,
experienceType: {type: Schema.Types.ObjectId, ref: 'ExperienceType'},
location: {type: Schema.Types.ObjectId, ref: 'Location'},
...} // others field of collection
,{
collection: 'experience'
});

get ExperienceType and Location of Experience when you find Booking:

Booking.findOne({_id: req.params.id})
.populate({path: 'experience',
populate: [{path: 'experienceType', select: 'name'}, {path: 'location', select: 'name'}],
})
.exec((err, booking) => {
if(err){
console.log(err);
}
else {
res.json(booking);
}
});

Or you can pass Object to the populate method as:

const myFilterObj = {};
const populateObj = {
path: "parentFileds",
populate: {
path: "childFileds",
select: "childFiledsToSelect"
},
select: "parentFiledsToSelect"
};
Model.find(myFilterObj)
.populate(populateObj).exec((err, data) => console.log(data) );