【问题标题】:Multiple populates - mongoosejs多个填充 - 猫鼬 js
【发布时间】:2021-10-25 06:55:26
【问题描述】:

只是一个简单的查询,例如模型中有一个双引用。

架构/模型

var OrderSchema = new Schema({

    user: {
        type    : Schema.Types.ObjectId,
        ref     : 'User',
        required: true
    },

    meal: {
        type    : Schema.Types.ObjectId,
        ref     : 'Meal',
        required: true
    },
});

var OrderModel = db.model('Order', OrderSchema);

查询

OrderModel.find()
    .populate('user') // works
    .populate('meal') // dont works
    .exec(function (err, results) {
         // callback
    });

我已经尝试过类似的东西

.populate('user meal')
.populate(['user', 'meal'])

事实上,只有一个填充物起作用。

那么,如何让两个种群工作?

【问题讨论】:

    标签: javascript node.js mongodb mongoose


    【解决方案1】:

    您已经使用了正确的语法:

    OrderModel.find()
        .populate('user')
        .populate('meal')
        .exec(function (err, results) {
             // callback
        });
    

    也许订单中的meal ObjectId 不在Meals 集合中?

    【讨论】:

    • 谢谢,对于其他人,他们也会这样做:仍然要确保您的 id 存在。
    • @mrzmyr 这里有什么问题?我有同样的经历,但不知道。
    • @JohnnyHK 为什么如果用户和餐点都被引用到同一个文档,则会抛出错误说MissingSchemaError {message: "Schema hasn't been registered for model "user".
    • 我不知道为什么文档让它看起来不起作用..
    【解决方案2】:

    更新:
    此解决方案仍然适用于 Mongoose 的 3.x 版本
    http://mongoosejs.com/docs/3.8.x/docs/populate.html
    但不再记录 >= 4.x 版本的 Mongoose ,因此@JohnnyHK 的答案是目前唯一有效的答案。

    原帖
    如果您使用的是 Mongoose >= 3.6,您可以传递一个以空格分隔的路径名字符串来填充:

    OrderModel.find()
        .populate('user meal')
        .exec(function (err, results) {
             // callback
        });
    

    http://mongoosejs.com/docs/populate.html

    【讨论】:

    • 确实简洁,但在我看来,每个填充一条路径使其更具可读性。
    • 这对我们很有用,因为我们可以传递一个数组并执行 arr.join(' ');
    • 您在哪里找到此文档,因为我在您提供的链接中找不到任何此类示例
    • @selftaught91 感谢您的提示,似乎新版本的猫鼬不再记录它,我也没有在新版本上测试它。因此,正如我在更新中建议的那样,您应该坚持 JohnnyHK 的回答
    【解决方案3】:

    这可能已经解决了,但这是我对 Mongodb > 3.6 中多重和深度人口的看法:

    OrderModel.find().populate([{
        path: 'user',
        model: 'User'
    }, {
        path: 'meal',
        model: 'Meal'
    }]).exec(function(err, order) {
        if(err) throw err;
        if(order) {
            // execute on order
            console.log(order.user.username); // prints user's username
            console.log(order.meal.value);    // you get the idea
        }
    });
    

    可能还有其他方法可以做到这一点,但这对于初学者(比如我)来说是非常易读的代码

    【讨论】:

    • 将一个数组放入调用填充是非常易读的。 FWIW 除非您可能想调用不同的模型,否则您不需要模型。 .populate([{path: 'user'}, {path: 'meal'}])
    【解决方案4】:

    在我看来,当您在同一级别上填充多个外部字段时,最好的解决方案是数组。我的代码显示我有多个不同级别的填充。

    const patients = await Patient.find({})
                        .populate([{
                            path: 'files',
                            populate: {
                                path: 'authorizations',
                                model: 'Authorization'
                            },
                            populate: {
                                path: 'claims',
                                model: 'Claim',
                                options: {
                                    sort: { startDate: 1 }
                                }
                            }
                        }, {
                            path: 'policies',
                            model: 'Policy',
                            populate: {
                                path: 'vobs',
                                populate: [{
                                    path: 'benefits'
                                }, {
                                    path: 'eligibility', 
                                    model: 'Eligibility'
                                }]
                            }
                        }]);
    

    如您所见,在需要填充文档的多个字段的地方,我将填充键封装在一个数组中并提供一组对象,每个对象都有不同的路径。在我看来,这是最强大、最简洁的方式。

    【讨论】:

      【解决方案5】:

      你可以使用array语法:

      let results = await OrderModel.find().populate(['user', 'meal']);
      

      您还可以从每个填充中选择您想要的属性:

      let results = await OrderModel.find().populate([{path: 'user', select: 'firstname'}, {path: 'meal', select: 'name'}]);
      

      【讨论】:

        【解决方案6】:

        你可以试试:

        OrderModel.find()
            .populate('user')
            .populate('meal')
            .exec(function (err, results) {
                 // callback
            });
        

        或使用数组选项

        OrderModel.find()
            .populate([
              {
                path: "path1",
                select: "field",
                model: Model1
              },
              {
                path: "path2",
                select: "field2",
                model: Model2
              }
            ])
            .exec(function (err, results) {
                 // callback
            });
        

        【讨论】:

          【解决方案7】:

          最新猫鼬v5.9.15 能够获取填充字段数组 这样你就可以了,

          .populate([ 'field1', 'field2' ])
          

          【讨论】:

            【解决方案8】:

            在模型文件中执行以下操作:-

             doctorid:{
                    type:Schema.Types.ObjectId, ref:'doctor'
                    },
                clinicid:{
                    type:Schema.Types.ObjectId, ref:'baseClinic'
                    }
            

            在用于添加运算符的 js 文件中使用类似:-

             const clinicObj = await BaseClinic.findOne({clinicId:req.body.clinicid})
             const doctorObj = await Doctor.findOne({ doctorId : req.body.doctorid}) ;
            **and add data as:-**
            const newOperator = new Operator({
                  clinicid:clinicObj._id,
                  doctorid: doctorObj._id
                });
            

            现在,在填充时

            apiRoutes.post("/operator-by-id", async (req, res) => {
                const id = req.body.id;
                const isExist = await Operator.find({ _id: id }).populate(['doctorid','clinicid'])
                if (isExist.length > 0) {
                  res.send(isExist)
                } else {
                  res.send("No operator found");
                }
              });
            

            【讨论】:

              【解决方案9】:

              我有同样的问题,但我的错误不是填充,我的模型有错误

              如果你这样做

              未修正

              user: {
               type: [Schema.Types.ObjectId],
               ref: 'User'
              } 
              

              正确

              user: [{
               type: Schema.Types.ObjectId,
               ref: 'User'
              }]
              

              你必须像这样在对象周围放置数组

              【讨论】:

                【解决方案10】:

                要在控制器/动作函数中使用对象数组填充多个字段,两者的模型已经在帖子的架构中引用

                post.find({}).populate('user').populate('comments').exec(function (err,posts)
                    {
                    
                    if(err)
                    {
                        console.log("error in post");
                    }
                    
                        return  res.render('home',{
                            h1:"home Page",
                            posts:posts,
                            
                            });      
                        });
                

                【讨论】:

                  【解决方案11】:

                  我认为您正在尝试可以访问的嵌套人口official docs

                  User.
                    findOne({ name: 'Val' }).
                    populate({
                      path: 'friends',
                      // Get friends of friends - populate the 'friends' array for every friend
                      populate: { path: 'friends' }
                    });
                  

                  【讨论】:

                    猜你喜欢
                    • 2020-10-17
                    • 2015-11-19
                    • 2015-07-13
                    • 2016-10-10
                    • 2019-09-16
                    • 2015-07-13
                    • 2020-01-17
                    • 2018-10-14
                    相关资源
                    最近更新 更多