在对象数组中查找ObjectId(Mongoose中的)$lookup

3

我有这两个架构:

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

我希望你能翻译关于IT技术的相关内容。以下是需要翻译的内容:

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

我尝试了以下方法:

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":"名称","email":"电子邮件","rating":{"rate":5,"articleID":"59074a357fe6a307981e7925"},"__v":0,"article-origin":[]}] 为什么这不起作用?
1个回答

1

由于组聚合操作不使用来自articles集合的文档,它只需要一个字段,即articleID进行分组,因此无需使用$lookup运算符。

有两种方法可以实现这一点。如果您的 MongoDB 服务器版本为 3.4 或更高,则可以应用 $divide$reduce$size 运算符来计算平均值,而无需先展开评级数组,如果数组很大,则可能会有一些性能影响。

考虑运行以下管道:

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

如果使用MongoDB版本3.2,则需要先$unwind评级数组:
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));
});

如果出于某些原因,您需要进行$lookup操作,则需要引用集合名称而不是模型名称,因此正确的聚合操作应该是:
User.aggregate([
    { "$unwind": "$rating" },
    {
        "$lookup": {
            "from": "articles", /* collection name here, not model name */
            "localField": "rating.articleID",
            "foreignField": "_id",
            "as": "article-origin"
        }
    },
    { "$match": { "article-origin.user" : mongoose.Types.ObjectId(article.user) } },
    {
        "$group": {
            "_id": "$_id",
            "avgRate": { "$avg": "$rating.rate" }
        }
    }
]).exec(function (err, result) {
    console.log(err);
    console.log(JSON.stringify(result));
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接