Ответ 1
В Mongoose появился новый метод Model.populate
для глубоких ассоциаций:
https://github.com/Automattic/mongoose/issues/1377#issuecomment-15911192
У меня есть модель Category
:
Category:
...
articles: [{type:ObjectId, ref:'Article'}]
Модель статьи содержит ref для Account model
.
Article:
...
account: {type:ObjectId, ref:'Account'}
Итак, с заполненной моделью articles
Category будет:
{ //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' }
Вопросы: как заполнить подполе (учетную запись) заполненного поля ([статьи])? Вот как я это делаю сейчас:
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
Я знаю, что это обсуждалось здесь: Mongoose: заполнить заполненное поле, но не найдено никакого реального решения
В Mongoose появился новый метод Model.populate
для глубоких ассоциаций:
https://github.com/Automattic/mongoose/issues/1377#issuecomment-15911192
Во-первых, обновите Мангуста 3 до 4, а затем используйте самый простой способ для глубокой популяции в мангусте, как показано ниже:
Предположим, у вас есть схема блога, имеющая userId в качестве ref Id, а затем в User у вас есть некоторый отзыв в качестве ref Id для обзора схемы. Итак, в принципе, у вас есть три схемы: 1. Блог 2. Пользователь 3. Обзор
И вы должны запросить в блоге, кому принадлежит этот блог и обзор пользователей. Таким образом, вы можете запросить свой результат как:
BlogModel
.find({})
.populate({
path : 'userId',
populate : {
path : 'reviewId'
}
})
.exec(function (err, res) {
})
Наведение на несколько уровней
Скажите, что у вас есть пользовательская схема, которая отслеживает друзей пользователя.
var userSchema = new Schema({
name: String,
friends: [{ type: ObjectId, ref: 'User' }]
});
Populate позволяет вам получить список друзей пользователя, но что, если вы также хотели пользователей друзей друзей? Укажите параметр populate, чтобы указать mongoose заполнить массив друзей всех друзей пользователя:
User.findOne({ name: 'Val' }).populate({
path: 'friends',
// Get friends of friends - populate the 'friends' array for every friend
populate: { path: 'friends' }
});
Ссылка: http://mongoosejs.com/docs/populate.html#deep-populate
Возможно, слишком поздно, но я написал плагин Mongoose для выполнения глубокой популяции на любых произвольных вложенных уровнях. При регистрации этого плагина вы можете заполнять статьи категорий и учетные записи только одной строкой:
Category.deepPopulate(categories, 'articles.account', cb)
Вы также можете указать параметры заполнения для управления такими вещами, как limit
, select
... для каждого заполненного пути. Ознакомьтесь с документацией плагина для получения дополнительной информации.
Самый простой способ выполнить это в 3.6 - это использовать 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);
});
});
Извините, что разорвал ваш пузырь, но там нет прямого поддерживаемого решения. Что касается Github issue # 601, он выглядит мрачным. Согласно примечаниям 3.6, похоже, что разработчики признали, что проблема удовлетворена ручным рекурсивным/глубоким населением.
Итак, из примечаний к выпуску рекомендуемый метод заключается в том, чтобы вложенные вызовы в обратном вызове, так что в вашей функции exec()
используйте categories.populate
для дальнейшего заполнения перед отправкой ответа.
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);
});
});
Следующий пример вдохновлен вопросом, заданным @codephobia, и заполняет два уровня многих отношений. Сначала выберите a user
, заполните его массив связанных order
и включите каждый 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[]
});
});
Это отлично работает в 3.8.8
, но должно работать в 3.6.x
.
Эта концепция глубокого населения. Здесь Календарь, Подписка, Пользователь, Квартира являются моделями мангуста ODM на разных уровнях.
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)
}
});