如果对象包含特定值,则从列表中返回对象

时间:2018-01-04 20:47:16

标签: mongodb mongodb-query aggregation-framework

我已经被困在这个问题上了一段时间,我觉得我已经接近了,但却无法找到解决方案。

我有一个如下所示的精简架构:

{
        "_id": {
            "$oid": "5a423f48d3983274668097f3"
        },
        "id": "59817",
        "key": "DW-15450",
        "changelog": {
            "histories": [
                {
                    "id": "449018",
                    "created": "2017-12-13T11:11:26.406+0000",
                    "items": [
                        {
                            "field": "status",
                            "toString": "Released"
                        }
                    ]
                },
                {
                    "id": "448697",
                    "created": "2017-12-08T09:54:41.822+0000",
                    "items": [
                        {
                            "field": "resolution",
                            "toString": "Fixed"
                        },
                        {
                            "field": "status",
                            "toString": "Completed"
                        }
                    ]
                }
            ]
        },
        "fields": {
            "issuetype": {
                "id": "1",
                "name": "Bug"
            }
        }
    }

我想抓住changelog.histories changelog.histories.items.toString值为Completed的所有"pipeline" => [ [ '$match' => [ 'changelog.histories.items.toString' => 'Completed' ] ], [ '$unwind' => '$changelog.histories' ], [ '$project' => [ 'changelog.histories' => [ '$filter' => [ 'input' => '$changelog.histories.items', 'as' => 'item', 'cond' => [ '$eq' => [ '$$item.toString', 'Completed' ] ] ] ] ] ] ]

以下是我的管道

{
"id": "448697",
"created": "2017-12-08T09:54:41.822+0000",
"items": [
    {
        "field": "resolution",
        "toString": "Fixed"
    },
    {
        "field": "status",
        "toString": "Completed"
    }
]

理想情况下,我希望以下内容返回

{{1}}

}

1 个答案:

答案 0 :(得分:1)

你可以尝试这样的事情。

db.changeLogs.aggregate([
  { $unwind: '$changelog.histories' },
  { $match: {'changelog.histories.items.toString': 'Completed'} },
  { $replaceRoot: { newRoot: "$changelog.histories" } }
]);

此解决方案执行COLLSCAN,因此在大量收集时会很昂贵。如果您有严格的性能要求,可以按如下方式创建索引。

db.changeLogs.createIndex({'changelog.histories.items.toString': 1})

然后,为了利用索引,您必须按如下方式更改查询。

db.changeLogs.aggregate([
  { $match: {'changelog.histories.items.toString': 'Completed'} },
  { $unwind: '$changelog.histories' },
  { $match: {'changelog.histories.items.toString': 'Completed'} },
  { $replaceRoot: { newRoot: "$changelog.histories" } }
]);

第一阶段过滤在Completed状态下具有至少一个历史记录项的changeLog文档。此阶段使用索引。第二阶段解开向量。第三阶段再次过滤具有Completed状态中的至少一个历史项的展开文档。最后,第四阶段将根返回项替换为文档。

修改

根据您的评论,这是一个替代解决方案,在保留的文档中保留idkey字段(同时保持使用索引)。

db.changeLogs.aggregate([
  { $match: {'changelog.histories.items.toString': 'Completed'} },
  { $unwind: '$changelog.histories' },
  { $match: {'changelog.histories.items.toString': 'Completed'} },
  { $project: { _id: 0, id: 1, key: 1, changelog: 1 }}
]);