【问题标题】:Mongodb Aggregate a $slice to get an element in exact position from a nested arrayMongodb 聚合一个 $slice 以从嵌套数组中获取精确位置的元素
【发布时间】:2016-03-04 17:18:29
【问题描述】:

我想从嵌套数组中检索一个值,它存在于数组中的确切位置。

我想通过对 name 执行 $slice[0,1] 然后为 value 执行 $slice[1,1] 来创建名称值对。

在尝试使用聚合之前,我想尝试在嵌套数组中进行查找。我可以对文档中的单个深度数组执行我想要的操作,如下所示:

{
"_id" : ObjectId("565cc5261506995581569439"),
"a" : [ 
    4, 
    2, 
    8, 
    71, 
    21
]
}

我应用以下内容:db.getCollection('anothertest').find({},{_id:0, a: {$slice:[0,1]}}) 我得到:

{
"a" : [ 
    4
]
}

这太棒了。但是,如果我要 $slice [0,1] 的数组位于 objectRawOriginData.Reports.Rows.Rows.Cells 的文档中怎么办?

如果我可以首先找到,那么我想应用与 AGGREGATE 相同的内容。

【问题讨论】:

    标签: mongodb mongodb-query slice aggregation-framework


    【解决方案1】:

    你最好的选择,尤其是如果你的应用程序还没有准备好发布,那就是推迟到 MongoDB 3.2 进行部署,或者至少在此期间开始使用候选发布版本。主要原因是“投影”$slice 不适用于聚合框架,其他形式的数组匹配投影也不适用。但这已在即将发布的版本中得到解决。

    这将为您提供一些新的运算符,例如 $slice 甚至是 $arrayElemAt,它们可用于按聚合管道中的位置来寻址数组元素。

    要么:

    db.getCollection('anothertest').aggregate([
        { "$project": {
            "_id": 0,
            "a": { "$slice": ["$a",0,1] }
        }}
    ])
    

    返回熟悉的:

    { "a" : [ 4 ] }
    

    或者:

    db.getCollection('anothertest').aggregate([
        { "$project": {
            "_id": 0,
            "a": { "$arrayElemAt": ["$a", 0] }
        }}
    ])
    

    这只是元素而不是数组:

    { "a" : 4 }
    

    在该版本以候选版本形式以外的形式可用之前,当前可用的运算符使数组的“第一个”元素变得非常容易:

    db.getCollection('anothertest').aggregate([
        { "$unwind": "$a" },
        { "$group": {
            "_id": "$_id",
            "a": { "$first": "$a" }
        }}
    ])
    

    通过在$unwind 之后使用$first 运算符。但是获取另一个索引位置变得非常迭代:

    db.getCollection('anothertest').aggregate([
        { "$unwind": "$a" },
        // Keeps the first element
        { "$group": {
            "_id": "$_id",
            "first": { "$first": "$a" },
            "a": { "$push": "$a" }
        }},
        { "$unwind": "$a" },
        // Removes the first element
        { "$redact": {
            "$cond": {
                "if": { "$ne": [ "$first", "$a" ] },
                "then": "$$KEEP",
                "else": "$$PRUNE"
            }
        }},
        // Top is now the second element
        { "$group": {
            "_id": "$_id",
            "second": { "$first": "$a" }
        }}
    ])
    

    等等,还有很多处理来改变它以处理可能比您正在寻找的“第 n 个”元素更短的数组。如此“可能”,但丑陋且性能不佳。

    还注意到“不是真的”与“索引位置”一起工作,并且纯粹是在值上匹配。所以重复值很容易被删除,除非每个数组元素有另一个唯一标识符可以使用。 Future $unwind 还具有投影数组索引的能力,这对于其他目的很方便,但其他运算符对于这种特定情况比该功能更有用。

    因此,为了我的钱,我会等到您拥有能够将其集成到聚合管道中的功能,或者至少重新考虑您为什么认为您需要它并可能围绕它进行设计。

    【讨论】:

    • 啊,太棒了。我会消化、实验和玩。感谢您抽出宝贵时间浏览此内容:)
    • 我浏览了最后一个,在第一节之后出现错误,出现“”异常:$redact 的表达式不应该返回除了变量 $$KEEP、$$DESCEND 和 $$PRUNE 之外的任何内容,但返回 {if: false, then: \"keep\", else: \"prune\"}",
    • @MattLightbourn 适合我直接在此处输入。整个"if/then/else" is meant to be wrapped in a $cond` 表达式,已被编辑。
    • 太棒了!谢谢你,我很想等到 3.2,但不幸的是,我们所有的系统都在以前认为的稳定版本上运行;我期待 3.2 :) 感谢您的帮助! :)
    • 使用 map_Reduce 有没有更简单的方法?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 2015-12-06
    • 1970-01-01
    • 2017-07-16
    相关资源
    最近更新 更多