在对象数组中对ObjectId进行$ lookup(Mongoose)

时间:2017-05-01 14:35:18

标签: node.js mongodb express mongoose

我有这两个架构:

module.exports = mongoose.model('Article', {
title : String,
text : String,
lang : { type: String, default: 'en'},
user : { type : mongoose.Schema.Types.ObjectId, ref: 'User' },
});



var userSchema = mongoose.Schema({
email        : String,
name         : String,
rating       : [{
                    _id: false,
                    articleID: {type: mongoose.Schema.Types.ObjectId, ref: 'Article'},
                    rate: Number
                }]
});
module.exports = mongoose.model('User', userSchema);

我希望计算用户的平均评分(其文章所有评分的平均值)。

我试过了:

User.aggregate([
            { $unwind: "$rating" },
            {
                "$lookup": {
                    "from": "Article",
                    "localField": "rating.articleID",
                    "foreignField": "_id",
                    "as": "article-origin"
                }
            }//,
            //{ $match: { "article-origin.user" : mongoose.Types.ObjectId(article.user) } }//,
            //{ $group : {_id : "$rating.articleID", avgRate : {  $avg : "$rating.rate" } } }
        ]).exec(function (err,result) {
            console.log(err);
            console.log(JSON.stringify(result));
        });

但没有成功,锁定总是返回字段article-origin null。

结果:{"_id":"590747e1af02570769c875dc","name":"name","email":"email","rating":{"rate":5,"articleID":"59074a357fe6a307981e7925"},"__v":0,"article-origin":[]}]

为什么这不起作用?

1 个答案:

答案 0 :(得分:0)

当然不需要 $lookup 运算符,因为组聚合操作不使用articles集合中的文档,它只需要一个字段,即{ {1}}用于分组。

有两种方法可以解决这个问题。如果您的MongoDB服务器版本为3.4或更高版本,那么 $divide $reduce $size 可以在此处应用运算符来计算平均值而无需求助 首先展平评级数组,如果数组很大,可能会产生一些性能影响。

考虑运行以下管道:

articleID

如果使用MongoDB 3.2版,那么首先需要 $unwind 评级数组:

User.aggregate([
    { "$match": { "_id" : mongoose.Types.ObjectId(article.user) } },
    {
        "$addFields": {
            "avgRate": {
                "$divide": [
                    {
                        "$reduce": {
                            "input": "$rating",
                            "initialValue": 0,
                            "in": { "$sum": ["$$value", "$$this.rate"] }
                        }
                    },
                    {
                        "$cond": [
                            { "$ne": [{ "$size": "$rating" }, 0] },
                            { "$size": "$rating" },
                            1
                        ]
                    }
                ]
            }
        }
    }
]).exec(function (err, result) {
    console.log(err);
    console.log(JSON.stringify(result));
});

如果出于某种原因需要 $lookup 操作,则需要引用集合名称,而不是模型名称,因此正确的聚合操作应该是

User.aggregate([
    { "$match": { "_id" : mongoose.Types.ObjectId(article.user) } },
    { "$unwind": "$rating" },
    {
        "$group": {
            "_id": "$_id",
            "avgRate": { "$avg": "$rating.rate" }
        }
    }
]).exec(function (err, result) {
    console.log(err);
    console.log(JSON.stringify(result));
});