【问题标题】:mongodb aggregate nested nested arraymongodb聚合嵌套嵌套数组
【发布时间】:2017-07-26 13:15:39
【问题描述】:

如何在位置 3 上找到具有 $match 的文档(仅数组“ndr”中的最后一项)。需要只在ndr的最后一个数组项中进行聚合搜索。

 {
    "_id" : ObjectId("58bd5c63a3d24b4a2e4cde03"),
    "name" : "great document",
    "country" : "us_us",
    "cdate" : ISODate("2017-03-06T12:56:03.405Z"),
    "nodes" : [ 
        {
            "node" : 3244343,
            "name" : "Best Node ever",
            "ndr" : [ 
                {
                    "position" : 7,
                    "cdate" : ISODate("2017-03-06T10:55:20.000Z")
                }, 
                {
                    "position" : 3,
                    "cdate" : ISODate("2017-03-06T10:55:20.000Z")
                }
            ]
        }
    ],
}

聚合后我需要这个结果

{
    "name" : "great document",
    "country" : "us_us",
    "cdate" : ISODate("2017-03-06T12:56:03.405Z"),
    "nodes" : [ 
        {
            "node" : 3244343,
            "name" : "Best Node ever",
            "ndr" : [ 
                {
                    "position" : 3,
                    "cdate" : ISODate("2017-03-06T10:55:20.000Z")
                }
            ]
        }
    ]
}

希望有人能帮助我。

【问题讨论】:

  • 嗨 Josch,欢迎来到 Stack Overflow。你能edit你的问题来展示你到目前为止所做的尝试,以及它出了什么问题吗?
  • 您的 MongoDB 服务器版本是多少?
  • 我有 MongoDB 版本 3.4

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

您将需要展开两个嵌套数组。

 db.<collection>.aggregate([
      { $unwind: '$nodes' },
      { $unwind: '$nodes.ndr'},
      { $group: {'_id':{'_id':'$_id', 'nodeID', '$nodes.node' },
                 'name':{'$last':'$name'},
                 'country':{'$last':'$country'},
                 'cdate':{'$last':'$cdate'},
                 'nodes':{'$last':'$nodes'}
                }
      },
      { $match : { nodes.ndr.position: 3 } }
  ]);

您可以在此处使用 $group 重新组合聚合结果并进行投影。我不确定你的最终结果应该是什么。

【讨论】:

  • 以及如何仅在最后一个数组项中进行搜索?
  • 对不起,我以为你在寻找一个特定的值 "position:3" 如果你需要找到最后一个你需要使用 $group 和 $last docs.mongodb.com/manual/reference/operator/aggregation/last
  • 嗨,我需要找到在最后一个数组项中位置为 3 的文档
  • 好的,我修改了答案以包括一个 $group 和 $last,这个按 _id 和 nodes.node 分组,这应该让您只搜索每个嵌套集的最后一个 nodes.ndr。
  • uhhh 这几乎是完美的,但是当我有多个节点时怎么办?目前他们将文档推送两次,不同的节点匹配。如何按文档 ID 分组并将第二个节点推入节点数组?
【解决方案2】:

您可以尝试使用 Mongo 3.4 版本进行以下聚合。

以下查询使用$arrayElemAt 运算符在ndr 数组中找到最后一项(-1),并将变量存储在last 中,使用$let 运算符为每个nodes 并比较last 变量@ 987654328@ 值使用$$ 表示法到3 并在数组[] 中包装nbr 元素,如果找到条目,否则返回空数组。

$map 运算符到达 nodes 数组内的 nbr 数组并投影更新后的 nbr 数组,同时映射其余的 nodes 字段。

$addFields 阶段将用新的nodes 覆盖现有的nodes,同时保留所有其他字段。

db.collection.aggregate([{
    $addFields: {
        nodes: {
            $map: {
                input: "$nodes",
                as: "value",
                in: {
                    node: "$$value.node",
                    name: "$$value.name",
                    ndr: {
                        $let: {
                            vars: {
                                last: {
                                    $arrayElemAt: ["$$value.ndr", -1]
                                }
                            },
                            in: {
                                $cond: [{
                                        $eq: ["$$last.position", 3]
                                    },
                                    ["$$last"],
                                    []
                                ]
                            }
                        }
                    }
                }
            }
        }
    }
}]);

更新:

您可以尝试$redact,如果它从给定的过滤器中找到匹配的位置,它将保留整个文档。

$map 投影truefalse 值基于每个节点的过滤器nbr 位置值和$anyElementTrue 将检查每个文档的先前布尔值并返回truefalse 值和$redact 将使用上述比较中的布尔值; true 值保留,false 值移除文档。

db.collection.aggregate([{
    $redact: {
        $cond: [{
            $anyElementTrue: {
                $map: {
                    input: "$nodes",
                    as: "value",
                    in: {
                        $let: {
                            vars: {
                                last: {
                                    $arrayElemAt: ["$$value.ndr", -1]
                                }
                            },
                            in: {
                                $cond: [{
                                        $eq: ["$$last.position", 3]
                                    },
                                    true,
                                    false
                                ]
                            }
                        }
                    }
                }
            }
        }, "$$KEEP", "$$PRUNE"]
    }
}]);

【讨论】:

  • 谢谢!如果没有与给定过滤器匹配的nodes.node.position,我如何删除整个文档?目前该文件正在准备中。
  • 添加了一个单独的解决方案,它将删除文档。
猜你喜欢
  • 1970-01-01
  • 2017-07-16
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
  • 2023-01-13
  • 2021-03-13
  • 2021-06-27
  • 2015-12-06
相关资源
最近更新 更多