Мангуст заселить врезанным

Я использую Mongoose.js и не могу решить проблему с документом иерархии 3 уровня.

Есть 2 способа сделать это.

Первый - без ссылок

C = new Schema({
    'title': String,
});

B = new Schema({
    'title': String,
    'c': [C]
});

A = new Schema({
    'title': String,
    'b': [B]
});

Мне нужно показать C запись. Как я могу заполнить / найти его, зная только _id of C?

Я попробовал использовать:

A.findOne({'b.c._id': req.params.c_id}, function(err, a){
    console.log(a);
});

Но я не знаю, как получить из returnet объект только c нужным мне объектом.

второй при работе с рефс:

C = new Schema({
    'title': String,
});

B = new Schema({
    'title': String,
    'c': [{ type: Schema.Types.ObjectId, ref: 'C' }]
});

A = new Schema({
    'title': String,
    'b': [{ type: Schema.Types.ObjectId, ref: 'B' }]
});

Как заполнить все записи B, C, чтобы получить иерархию?

Я пытался использовать что-то вроде этого:

A
.find({})
.populate('b')
.populate('b.c')
.exec(function(err, a){
    a.forEach(function(single_a){
        console.log('- ' + single_a.title);
        single_a.b.forEach(function(single_b){
            console.log('-- ' + single_b.title);
            single_b.c.forEach(function(single_c){
                console.log('--- ' + single_c.title);
            });
        });
    });
});

Но он вернет undefined для single_c.title. Есть ли способ его заселить?

Благодарю.

 JohnnyHK28 янв. 2015 г., 02:56
Было бы хорошо выбрать новый принятый ответ сейчас, когда это поддерживается.

Ответы на вопрос(4)

По состоянию на Мангуст 3.6возможность рекурсивного заполнения связанных документов в запрос был добавлен. Вот пример того, как вы можете это сделать:

 UserList.findById(listId)
         .populate('refUserListItems')
         .exec(function(err, doc){
             UserListItem.populate(doc.refUserListItems, {path:'refSuggestion'},
                   function(err, data){
                        console.log("User List data: %j", doc);
                        cb(null, doc);
                   }
             );     
          });           

В этом случае я заполняю массив idвrefUserListItems' с их ссылочными документами. Затем результат запроса передается в другой заполненный запрос, который ссылается на поле исходного заполненного документа, который я также хочу заполнить - 'refSuggestion.

Обратите внимание на второе (внутреннее) заполнение - здесь происходит магия. Вы можете продолжать вкладывать эти заполнители и прикреплять все больше и больше документов, пока не построите свой график так, как вам это нужно.

Требуется немного времени, чтобы понять, как это работает, но если вы работаете через это, это имеет смысл.

 fusio14 авг. 2013 г., 17:55
определенно! Спасибо :)
 Cédric NICOLAS02 июл. 2015 г., 22:52
это работает, но глубокое заполнение, данное Буу Нгуеном выше, более удобно. Не нужно делать вложенные циклы ..
 Harshit Laddha01 нояб. 2015 г., 20:40
Что делать, если мне нужно найти документы, а не один документ, я должен выполнить итерацию по каждому из них, чтобы заполнить внутренний путь, или есть способ сделать это для всех них
 Daniel Kobe11 апр. 2016 г., 19:08
Почему Дон'т вам нужно exec во второй раз @BoxerBucks
 BoxerBucks17 авг. 2015 г., 15:48
@steampowered - Какая часть? Вы можете обернуть все это в функцию, которая возвращает обещание и разрешает обещание в обратном вызове .populate. Похоже, что .populate также возвращает обещание, чтобы вы могли зафиксировать это обещание в любой из функций .populate и затем вызвать .then для него, когда захотите его запустить.
 steampowered14 авг. 2015 г., 22:13
Как я могу сделать это, используя обещания?
 steampowered17 авг. 2015 г., 17:48
@BoxerBucks Я решил вернуть обещание, что.populate() возвращается в цепочке.then() функции, и, наконец, запустить его с последним.then(), Я думаю, что это выглядит чище, чем вложенность n уровня населения.stackoverflow.com/a/32018947/404699
Решение Вопроса

Скажи, что у тебя естьпользователь схема, которая отслеживает пользователяс друзьями.

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

во-первыхpopulate() позволяет получить список друзей пользователя. Но что, если вы также хотели пользователя?друзья друзей? В этом случае вы можете указатьpopulate возможность сказать мангусту, чтобы заселитьfriends массив всех пользователей 'Друзья:

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

 BoxerBucks05 июн. 2013 г., 19:37
К вашему сведению - это было решено в версии 3.6 -github.com/LearnBoost/mongoose/wiki/3.6-Release-Notes
 Kefka13 мая 2016 г., 18:24
Не имеет смысла опровергать этот ответ, потому что это неверно прямо сейчас! @GianPaJ обновить свой ответ, а не удалять.
 BoxerBucks14 авг. 2013 г., 17:12
@fusio - я добавил ответ в качестве примера того, как я это сделал
 Gianfranco P.31 окт. 2012 г., 18:45
Тот же ответ от Аарона из аналогичного вопросаstackoverflow.com/q/11137239/728287
 a2013 окт. 2015 г., 12:25
Проголосовал, так как этот ответ сейчас недействителен.
 fusio14 авг. 2013 г., 00:51
@BoxerBucks не могли бы вы привести пример? (случай с рефсами)
 Gianfranco P.14 окт. 2015 г., 12:05
Я удалю мой ответ, как только @ Oleg2tor примет правильный ответ.

Я опоздал на это, но я написалПлагин Mongoose это делает его чрезвычайно простым для выполнения глубокой модели населения. Для вашего примера, вы можете сделать это, чтобы заполнитьb а также :c

A.find({}, function (err, docs) {
  A.deepPopulate(docs, 'b.c', cb)
}

Вы также можете указатьМангуст заселить варианты для каждого из населенных путей, как это:

A.deepPopulate(docs, 'b.c', {
  b: { 
    select: 'name'
  }
}, cb)

Проверьте плагиндокументация для дополнительной информации.

 steampowered14 авг. 2015 г., 23:28
Это выглядит действительно круто. Я мог бы использовать его в производстве, когда он станет более зрелым.
 Matthias Max24 февр. 2016 г., 21:19
Isn»т б: должен быть с:?

как это (даже в другой базе данных или экземпляре)

A
.find({})
.populate({
  path: 'b', 
  model: 'B',
  populate: {
    path: 'c',
    model: 'C'
  }
})
.exec(function(err, a){});
 pravin18 авг. 2016 г., 11:42
Небольшое отклонение .. что будет еслиB = new Schema({ 'title': String, 'c': [{ type: Schema.Types.ObjectId, ref: 'C' }], 'cc': [{ type: Schema.Types.ObjectId, ref: 'C' }] }); Как мне заполнить как c, так и cc?
 Trinh Hoang Nhu18 авг. 2016 г., 19:02
Вы можете сделать .populate ('c') .Populate (»куб.см»в цепочку заселить вот так. Это то, что вы хотите?
 Doug Molineux12 янв. 2016 г., 00:22
Это обязательно должно быть помечено как правильный ответ +1
 Trinh Hoang Nhu12 янв. 2016 г., 00:23
Это доступно только в более новой версии, так что ...
 Trinh Hoang Nhu18 авг. 2016 г., 19:04
Или даже B.populate ([{path: 'c'}, {дорожка: 'куб.см»}])Я'
 CENT1PEDE09 мар. 2016 г., 06:45
Это должен быть правильный ответ. +1

Ваш ответ на вопрос