MongoDB获得SubDocument

时间:2014-01-14 12:25:17

标签: mongodb mongodb-query aggregation-framework

我想从MongoDB中的文档中检索子文档。我有以下文件:

{
    "_id" : "10000",
    "password" : "password1",
    "name" : "customer1",
    "enabled" : true,
    "channels" : [ 
        {
            "id" : "10000-1",
            "name" : "cust1chan1",
            "enabled" : true
        }, 
        {
            "id" : "10000-2",
            "name" : "cust1chan2",
            "enabled" : true
        }
    ]
}

我想要的结果是:

{
    "id" : "10000-1",
    "name" : "cust1chan1",
    "enabled" : true
}

但是,到目前为止我能做的最好的事情是使用以下查询:

db.customer.find({"channels.id" : "10000-1"}, {"channels.$" : 1, "_id" : 0})

但这给了我以下结果:

{
    "channels" : [ 
        {
            "id" : "10000-1",
            "name" : "cust1chan1",
            "enabled" : true
        }
    ]
}

有谁知道是否有可能编写一个能够给我想要的结果的查询?任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:8)

您可以使用Aggregation Framework执行此操作。查询将类似于:

db.customer.aggregate([
    {$unwind : "$channels"},
    {$match : {"channels.id" : "10000-1"}},
    {$project : {_id : 0, 
                 id : "$channels.id", 
                 name : "$channels.name", 
                 enabled : "$channels.enabled"}}
])

答案 1 :(得分:0)

使用MongoDB 3.4.4和更高版本,聚合框架提供了许多运算符,可用于返回所需的子文档。

考虑运行一个聚合管道,该管道使用单个 $replaceRoot 阶段将筛选后的子文档提升到顶层并替换所有其他字段。

过滤子文档需要 $filter 运算符,该运算符根据指定条件选择要返回的数组子集,即返回仅包含与条件匹配的那些元素的数组。然后,您可以使用 $arrayElemAt 运算符

将单个数组元素转换为文档

总体运行此聚合操作将产生所需的结果:

db.customer.aggregate([
    { "$replaceRoot": { 
        "newRoot": {
            "$arrayElemAt": [
                { "$filter": {
                   "input": "$channels",
                   "as": "channel",
                   "cond": { /* resolve to a boolean value and determine if an element should be included in the output array. */
                       "$eq": ["$$channel.id", "10000-1"]
                    } 
                } },
                0 /* the element at the specified array index */
            ]
        }
    } }
])

输出

{
    "id" : "10000-1",
    "name" : "cust1chan1",
    "enabled" : true
}