mongodb聚合嵌套嵌套数组

时间:2017-03-06 15:31:45

标签: mongodb mongodb-query aggregation-framework

如何在位置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")
                }
            ]
        }
    ]
}

我希望有人能帮助我。

3 个答案:

答案 0 :(得分:0)

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

 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重新组合聚合结果并进行投影。我不确定你的最终结果应该是什么。

答案 1 :(得分:0)

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

以下查询使用(-1)数组中的$arrayElemAt运算符查找最后一项ndr,并使用last运算符将变量存储在$let中{ {1}}并使用nodes表示法将last变量position值与$$进行比较,并将3元素包含在数组nbr中找到并返回空数组。

[]运算符访问$map数组中的nbr数组,并在映射其余nodes字段时投影更新的nbr数组。

nodes阶段会覆盖现有的$addFieldsnodes,同时保留所有其他字段。

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位置值和true的过滤器投影falsenbr值将检查前一个布尔值每个文档的值并返回$anyElementTruetrue值,false将使用上述比较中的booelan值;保留的真值和删除文档的假值。

$redact

答案 2 :(得分:0)

Woodsy的解决方案对我来说非常适合。现在我需要计算每个节点的$ avg以及从“node.bsr.rank”以百分比(loos或win)进入给定数量的最后几天之间的开发。

喜欢这个结果

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