猫鼬:人口众多(人口众多)


75

我有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' }

问题是:如何填充已填充字段([articles])的子字段(帐户)?这是我现在的做法:

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

我知道在这里进行了讨论:猫鼬:填充一个已填充的字段,但未找到实际的解决方案


3
就像rroxysam所说的那样,.populate({path : 'userId', populate : {path : 'reviewId'}}).exec(...)似乎是递归逻辑,这很有意义。其作品!
Ewertom Moraes 17-4-30的

自发布此问题以来,对Mongoose的更新已解决了此问题。下面是文档: 在多个层次填充
矮胖组块

Answers:



142

首先,将猫鼬3更新为4,然后使用最简单的方法对猫鼬进行深层填充,如下所示:

假设您有Blog模式,其userId为参考ID,然后在User中,您有一些参考为schema Review的参考ID。因此,基本上,您具有三个架构:1.博客2.用户3.审阅

并且,您必须从博客中查询,该用户拥有此博客和用户评论。因此,您可以查询结果为:

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

  })

9
如果我已经阅读了您的答案,并且没有将一个小时的时间浪费在上面的答案上!
阿敏·贾法里

5
感谢您显示查询的结构,而不仅仅是链接到文档。很棒!
特纳霍顿

8
这应该是正确的答案。感谢@techyaura
jpincheira

当您要填充两个字段时,如何填充第二级?当我使用select时,它只会一直为我返回最后一个字段:因为我只想返回第二级文档中的特定字段
bzlight

您的解决方案在2020年仍然可以使用。感谢分享!
Niyongabo

35

跨多个级别填充

假设您有一个用户架构,该架构可以跟踪用户的朋友。

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

“填充”可让您获取用户的朋友列表,但是如果您还想要用户的朋友的朋友怎么办?指定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


20

可能为时已晚,但是我写了一个Mongoose插件来执行任意嵌套级别的深度填充。注册此插件后,您只需一行即可填充类别的文章和帐户:

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

您还可以指定填入选项来控制之类的东西limitselect......每个填充路径。查看插件文档以获取更多信息。


9

在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);
    });
});

1
我很好奇,如果user.favorites是一个数组,您将如何做同样的事情?
codephobia 2014年

同样的方式。摆脱掉.thing
chovy

6

或者,您可以将Object传递给populate方法,如下所示:

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

3

抱歉,您的泡沫破灭了,但尚无直接支持的解决方案。至于Github问题#601,它看起来很严峻。根据3.6版本说明,开发人员似乎已经意识到该问题对手动递归/深度填充很满意。

因此,从发行说明中,推荐的方法是将已填充的调用嵌套在回调中,因此在您的exec()函数中,可使用categories.populate它在发送响应之前进一步填充。


3

这个概念是深人口。这里的日历,订阅,用户,公寓是不同级别的猫鼬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)
                            }
                   });

2
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,填充其相关的orders数组并包含每个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


0

如果要在populate中选择多填充,则应尝试以下方式:

我有预订模式:

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

体验模式:

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

得到ExperienceType和地点经验,当你发现订房

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);
    }
  });
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.