mongodb - 如何使用 MongoDB 从聚合结果中投影附加数据?

标签 mongodb mongodb-query aggregation-framework

我正在学习 MongoDB 并尝试对集合进行分组。 我正在寻找的是按年份分组,获取最大“平均注释”字段并显示与此平均值相关的文档的字段主名称

例如,如果我有:

Name    | Average   | Year
Name_01 | 7.56      | 1995
Name_02 | 8.96      | 1995
Name_03 | 3.25      | 2005
Name_04 | 4.36      | 2005
Name_05 | 7.52      | 2020

我需要:

Name    | Average   | Year
Name_02 | 8.96      | 1995
Name_05 | 7.52      | 2020
Name_04 | 4.36      | 2005

我已经完成了小组和最大值。这是我的代码:

db.foobar.aggregate([
    {
        $group: { _id: '$year_published', max: { $max: '$statistics.average' }}
    },
    {
        $project: { _id: 1, max: 1 }
    }, 
    {
        $sort: { max: -1 }
    }    
])

这给了我这样的结果:

{
    "result" : [ 
        {
            "_id" : 1999,
            "max" : 8.0343000000000000
        }, 
        {
            "_id" : 1985,
            "max" : 7.8833299999999999
        }
        // An so on...
}

但我还想投影与“max”相关的文档的主要名称,以获得如下内容:

 {
    "result" : [ 
        {
            "_id" : 1999,
            "max" : 8.0343000000000000,
            "name": "Foo Bar"
        }, 
        {
            "_id" : 1985,
            "max" : 7.8833299999999999,
            "name": "Lorem Ipsum"
        }
        // An so on...
}

注意:问题的下一部分增加了名称的复杂性(因为我的文档结构)。这不是我现在主要关心的问题,但我将其添加到问题中以反射(reflect)我的所有问题。

主要名称有点难以获取。对于每个文档,我都有一个这样的对象数组:

{
    "names" : [ 
        {
            "type" : "primary",
            "value" : "Foo bar"
        }, 
        {
            "type" : "alternate",
            "value" : "Foo foo"
        }, 
        {
            "type" : "alternate",
            "value" : "Bar bar"
        }
    ]
}

我想要获取的是“主要”类型的名称(即我的示例中的“Foo bar”)。

这是我的文档的结构:

{
    "_id" : ObjectId("56338f2bdc99b8ec22a43328"),
    "names" : [ 
        {
            "type" : "primary",
            "value" : "Foo bar"
        },
        {
            "type" : "alternate",
            "value" : "Barr foo"
        }
    ],
    "year_published" : 1992
    "statistics" : {
        "average" : 6.6057699999999997
    }
}

我想我还没有做到这一点,但我不知道该怎么做......你能帮我吗?

最佳答案

如果您希望特定文档中的“配对”值具有“最大值”,那么 $max 不适合您。相反,你需要做的是 $sort先获取数据,然后使用 $first运算符。

db.foobar.aggregate([
    { "$sort":  { "year_published": 1, "statistics.average": -1 } },
    { "$group": { 
        "_id": "$year_published", 
        "max": { "$first": "$statistics.average" }},
        "name": { 
            "$first": {
                "$setDifference": [
                    { "$map": {
                        "input": "$names",
                        "as": "name",
                        "in": {
                            "$cond": {
                                "if": { "$eq": [ "$$name.type", "primary" ] },
                                "then": "$$name.value",
                                "else": false
                            }
                        }
                    }},
                    [false]
                ]
            }
        }
    }},
    { "$unwind": "$name" }
])

$first$last 运算符作用于“分组边界”数据。这意味着它们从用于分组 _id 的值的开头或结尾处出现的属性返回数据。

这就是为什么您首先要“排序”,以便文档按顺序进行选择。

相比之下,$max$min 只需从示例文档中的任意位置选取“max/min”值。如果这就是您想要的,那很好,但如果您想要“相关”字段,那么您必须首先排序。

这就是它的基础知识。处理数组过滤的另一部分最好使用 $map 来完成。和 $setDifference组合如图所示。 $map 允许通过 $cond 测试条件对每个数组元素“内联”,并根据 true 或 false 返回值。结果当然仍然是一个等长的数组。

$setDifference 本质上会过滤掉任何返回为 false 的内容,因此唯一剩下的应该是“primary”。仍然是一个数组,这就是为什么仍然使用 $unwind 的原因,尽管它只是一个单元素数组。

future 的 MongoDB 版本将通过 $filter$arrayElemAt 做得更好。下面是一瞥:

db.foobar.aggregate([
    { "$sort":  { "year_published": 1, "statistics.average": -1 } },
    { "$group": { 
        "_id": "$year_published", 
        "max": { "$first": "$statistics.average" }},
        "name": { 
            "$first": {
                "$arrayElemAt": [
                    { "$filter": {
                        "input": "$names",
                        "as": "name",
                        "cond": {
                            "$eq": [ "$$name.type", "primary" ]
                        }
                    }},
                    0
                ]
            }
        }
    }}
])

但是这些都不会改变“先排序”的基本规则,然后从分组边界中选取值。

关于mongodb - 如何使用 MongoDB 从聚合结果中投影附加数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33495346/

相关文章:

javascript - 如果我链接 .sort(), Mongoose 查询会失败

php - MongoDB RegEx 引擎完整性

MongoDB在列表列表中查找值

mongodb - 在 MongoDB shell FIND 脚本中格式化日期值

node.js - 批量写入 - 类型错误 : Cannot create property '$set' on number '0' at applyTimestampsToUpdate - mongoose or mongodb

MongoDB - 子文档内的上一个和下一个

mongodb - 获取 MongoDB 聚合管道中 $group 之后的输入文档中的字段

mongodb - 从 $lookup 中获取数组中元素的过滤计数以及整个文档

mongodb - 为与官方 Mongo Go 驱动程序 mongo-go-driver(mgo 中的 session.SetMode)的 session 将一致性规则设置为单调

mongodb - MongoDB中通过ObjectId而不是image_name获取图像