Подпункт субположения заполнения Mongoose

У меня есть эта настройка в моем MongoDB

Продукты:

title: String
comments: [] // of objectId's

Комментарии:

user: ObjectId()
item: ObjectId()
comment: String

Здесь моя схема Mongoose:

itemSchema = mongoose.Schema({
    title: String,
    comments: [{ type: Schema.Types.ObjectId, ref: 'comments' }],
});

Item = mongoose.model('items', itemSchema);

commentSchema = mongoose.Schema({
    comment: String,
    user: { type: Schema.Types.ObjectId, ref: 'users' },
});

Comment = mongoose.model('comments', commentSchema);

Здесь я получаю свои предметы вместе с комментариями:

Item.find({}).populate('comments').exec(function(err, data){
    if (err) return handleError(err);
    res.json(data);
});

Как заполнить массив комментариев соответствующим пользователем? Поскольку каждый комментарий имеет пользователь ObjectId()?

Ответ 1

Как полный пример вызова, заполняющего объекты результата:

Item.find({}).populate("comments").exec(function(err,data) {
    if (err) return handleError(err);

    async.forEach(data,function(item,callback) {
        User.populate(item.comments,{ "path": "user" },function(err,output) {
            if (err) throw err; // or do something

            callback();
        });
    }, function(err) {
        res.json(data);
    });

});

Вызов .populate() в форме, выведенной из модели, принимает в качестве первого аргумента документ или массив. Таким образом, вы просматриваете возвращаемые результаты для каждого элемента и вызываете их таким образом в каждом массиве "комментарии". "Путь" сообщает функции, что она соответствует.

Это выполняется с использованием "async" версии forEach, поэтому она не блокируется, но, как правило, после всех манипуляций все элементы ответа не только заполняются комментариями, но и сами комментарии имеют соответствующий "пользователь", подробности.

Ответ 2

Еще один способ (проще) сделать это:

Item
  .find({})
  .populate({
	path:     'comments',			
	populate: { path:  'user',
		    model: 'users' }
  })
  .exec(function(err, data){
    if (err) return handleError(err);
    res.json(data);
});

Ответ 3

Simpler

Item
  .find({})
  .populate({
    path: 'comments.user',
    model: 'users' }
  })
  .exec(function(err, data){
    if (err) return handleError(err);
    res.json(data);
});

Ответ 4

Чтобы добавить один последний метод, который люди могут использовать для выбора только определенных полей из поддокументов, вы можете использовать следующий синтаксис "select":

  Model.findOne({ _id: 'example' })
    .populate({ 
      path: "comments", // 1st level subdoc (get comments)
      populate: { // 2nd level subdoc (get users in comments)
        path: "user",
        select: 'avatar name _id'// space separated (selected fields only)
      }
    })
    .exec((err, res) => { 
        // etc
     });

Ответ 5

Для заполнения вложенного документа и заполнения из нескольких схем

ProjectMetadata.findOne({id:req.params.prjId})
.populate({
    path:'tasks',
    model:'task_metadata',
    populate:{
        path:'assigned_to',
        model:'users',
        select:'name employee_id -_id' // to select fields and remove _id field

    }
})
.populate({
    path:'client',
    model:'client'
})
.populate({
    path:'prjct_mgr',
    model:'users'
})
.populate({
    path:'acc_exec',
    model:'users'
})
.populate({
    path:'prj_type',
    model:'project_type'
}).then ( // .. your thing

или вы можете сделать это следующим образом..

   ProjectMetadata.findOne({id:req.params.prjId})
    .populate(
        [{
        path:'tasks',
        model:TaskMetadata,
        populate:[{
            path:'assigned_to',
            model:User,
            select:'name employee_id'
        },
        {
            path:'priority',
            model:Priority,
            select:'id title'
        }],
        select:"task_name id code assign_to stage priority_id"
    },
    {
        path:'client',
        model:Client,
        select:"client_name"
    },
    {
        path:'prjct_mgr',
        model:User,
        select:"name"
    },
    {
        path:'acc_exec',
        model:User,
        select:'name employee_id'
    },
    {
        path:'poc',
        model:User,
        select:'name employee_id'
    },
    {
        path:'prj_type',
        model:ProjectType,
        select:"type -_id"
    }

])

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

Ответ 6

попробуйте это найти работу Project и получите связанное с проектом заполнение Task и Perticular Task User find

db.Project.find()
.populate({
    path: 'task',
    populate: { path: 'user_id'}
})
.exec(async(error,results)=>{

})