MongoDB聚合投影

时间:2015-03-03 12:56:05

标签: mongodb mongodb-query

如果我有如下收藏品:

db.cafe.insert({name: "Cafe1", customers: [{name: "David", foods: [{name : "cheese"}, {name: "beef"}]}, {name: "Bill", foods: [{name: "fish"}]} ]})


    db.cafe.find().pretty()
{
    "_id" : ObjectId("54f5ae58baed23b7a34fccb6"),
    "name" : "Cafe1",
    "customers" : [
        {
            "name" : "David",
            "foods" : [
                {
                    "name" : "cheese"
                },
                {
                    "name" : "beef"
                }
            ]
        },
        {
            "name" : "Bill",
            "foods" : [
                {
                    "name" : "fish"
                }
            ]
        }
    ]
}

如何为名为“David”的人提取仅包含食物对象的数组。 期望的产出只是食物的一系列,即:

[{name: "cheese"}, {name: "beef"}]

我尝试了一个聚合管道来解开咖啡馆的顾客,然后根据名称进行匹配然后预测食物,例如:

db.cafe.aggregate( [{$unwind : "$customers"}, {$match : {"customers.name": "David"}}, {$project : {"customers.foods": 1, _id : 0} 

}] ).pretty()
{
    "customers" : {
        "foods" : [
            {
                "name" : "cheese"
            },
            {
                "name" : "beef"
            }
        ]
    }
}

这似乎接近于预期的结果,但是,我留下的问题是我想要的食物被引用为属性customers.foods下的数组。我希望结果直接是:

[
            {
                "name" : "cheese"
            },
            {
                "name" : "beef"
            }
        ]

有没有办法可以实现所需的输出?

2 个答案:

答案 0 :(得分:2)

你的投射错误。

db.cafe.aggregate( [
    { "$match" : { "customers.name": "David" }},
    { "$unwind" : "$customers" }, 

    { "$project" : { "foods": "$customers.foods", "_id": 0 }}
])

<强>输出

{ "foods" : [ { "name" : "cheese" }, { "name" : "beef" } ] }

答案 1 :(得分:1)

您还可以通过常规查询得到(非常非常接近)您想要的输出:

> db.cafe.find({ "customers.name" : "David" }, { "customers.$.foods" : 1, "_id" : 0 })
{ "customers" : [ { "name" : "David", "foods" : [ { "name" : "cheese" }, { "name" : "beef" } ] } ] }

客户将是一个仅包含name : "David"的第一个对象的数组。您应该更喜欢这种聚合方法,因为它的性能要高得多。您可以在客户端代码中提取foods数组。