猫鼬:人口密集(人口稠密)

时间:2013-09-18 08:45:40

标签: mongodb mongoose populate

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

我知道这里讨论过:Mongoose: Populate a populated field但没有找到真正的解决方案

10 个答案:

答案 0 :(得分:57)

首先,更新mongoose 3到4&然后使用最简单的方法在猫鼬中进行深度人口统计,如下所示:

假设您有Blog架构,其userId为ref Id&然后在用户中,您有一些评论作为架构审查的参考ID。所以基本上,你有三个架构: 1.博客 2.用户 3.审核

并且,您必须从博客查询,哪个用户拥有此博客&用户评论。 因此,您可以将结果查询为:

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

 })

答案 1 :(得分:28)

跨多个级别填充

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

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

Populate可以让你获得用户朋友的列表,但是如果你还想要用户的朋友朋友呢?指定populate选项以告诉mongoose填充所有用户朋友的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

答案 2 :(得分:20)

Mongoose现在有一个新方法Model.populate用于深层关联:

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

答案 3 :(得分:17)

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

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

您还可以指定populate options来控制每个填充路径的limitselect ...等内容。查看插件文档以获取更多信息。

答案 4 :(得分:8)

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

答案 5 :(得分: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) );

答案 6 :(得分:3)

很抱歉破坏了你的泡沫,但是没有直接支持的解决方案。至于Github issue #601,它看起来很严峻。根据{{​​3}},看起来开发人员承认这个问题对手动递归/深度人口感到满意。

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

答案 7 :(得分: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提出的问题,并填充了许多关系的两个层次。首先获取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中使用。

答案 8 :(得分:0)

这个概念是深层人口。 这里的Calendar,Subscription,User,Apartment是不同级别的猫鼬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)
                            }
                   });

答案 9 :(得分:0)

如果要选择内部填充,则应尝试以下方式:

我有预订模式:

AAA

体验模式:

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