MongoDB $将嵌入式文档投影到根级

时间:2016-02-03 17:11:18

标签: javascript mongodb mongodb-query

使用聚合管道,我试图将嵌入式文档投影到根级别而不单独投影每个字段。

例如,我想将此集合中的name投影到根级别:

[
    {
        _id: "1",
        name: {
            firstName: "John",
            lastname: "Peters"
        }
    },
    {
        _id: "2",
        name: {
            firstName: "Mary",
            lastname: "Jones"
        }
    }
]

这就是我要找的:

[
    {
        firstName: "John",
        lastname: "Peters"
    },
    {
        firstName: "Mary",
        lastname: "Jones"
    }
]

有没有办法在不单独投影每个字段的情况下执行此操作?我不想这样做:

db.collection.aggregate(
    [
        {
            $project : {
                "_id" : 0,
                "firstName" : "$name.firstName",
                "lastName" : "$name.lastName"
            }
        }
    ]

5 个答案:

答案 0 :(得分:5)

MongoDB 3.4在聚合管道中有一个新阶段 - (* OPTION 1 *) Store modified code (as data) into code segment; Jump to new code or an intermediate location; Execute new code; ,它完全符合要求。

https://docs.mongodb.com/manual/reference/operator/aggregation/replaceRoot/

答案 1 :(得分:2)

以下是使用JavaScript变量的解决方案。

# Set Object for what to project
var projectWhat = {'_id' : 0};

# Fill Object with keys
Object.keys(db.coll.findOne().name).forEach(function(x){
    projectWhat[x] = "$name." + x;
});

# Do Aggregate
db.coll.aggregate([{$project : projectWhat}])

输出将是

{ "firstName" : "John", "lastname" : "Peters" }
{ "firstName" : "Mary", "lastname" : "Jones" }

希望这有帮助。

答案 2 :(得分:1)

这可以通过使用$set使用name子文档中的值更新所有文档来实现:

db.collection.find({ "name": {"$exists": 1 } }).forEach(function(doc) {
    var setName = {};
    for ( var k in doc.name ) {
        setName[k] = doc.name[k];
    }
    db.collection.update(
        { "_id": doc._id },
        { "$set": setName, "$unset": "name" }
    );
})

虽然我建议您使用$project因为它比此解决方案更高效,但我可以理解为什么您不想使用$project

答案 3 :(得分:0)

Mongo 4.2开始,$replaceWith聚合运算符可用于将一个文档替换为另一个文档(在我们的示例中为一个子文档):

// { _id: "1", name: { firstName: "John", lastname: "Peters" } }
// { _id: "2", name: { firstName: "Mary", lastname: "Jones"  } }
db.collection.aggregate({ $replaceWith: "$name" })
// { firstName: "John", lastname: "Peters" }
// { firstName: "Mary", lastname: "Jones" }

答案 4 :(得分:0)

您可以像这样使用 $replaceRoot

db.collection.aggregate(
    [
        {
            $replaceRoot : {
                newRoot: {"$name"}
            }
        }
    ]
)

此外,如果您希望在根文档中有一个字段保留,您可以使用 $mergeObjects 将其与您的嵌入对象组合:

db.collection.aggregate(
    [
        {
            $replaceRoot : {
                newRoot: {
                   $mergeObjects: [
                      {"_id": "$_id"},
                      "$name"
                   ]
                }
            }
        }
    ]
)