【问题标题】:MongoDB Aggregation Query- Rename Fields Returned from Within Embedded DocumentsMongoDB 聚合查询 - 重命名从嵌入式文档中返回的字段
【发布时间】:2014-11-03 14:25:30
【问题描述】:

我目前正在使用聚合运算符来返回包含嵌入(子)文档数组的文档。我想重命名数组的字段名,还要重命名数组嵌入文档中的字段名。

例如,对于投影,我想将数组从“friends”重命名为“buddies”,并且我还想将嵌入文档中的字段从“name”重命名为“nickName”。我可以在聚合操作中执行此操作吗?如果可以,如何操作?

以下是源文档的示例:

[
    {
        _id: ObjectID,
        name: 'Matthew',
        friends: [
            {name: 'Slim', age: '32'},
            {name: 'buba', age: '36'}
        ]
    }
]

结果应该是这样的:

[
    {
        _id: ObjectID,
        name: 'Matthew',
        buddies: [
            {nickName: 'Chris', age: '32'},
            {nickName: 'Jim', age: '36'}
        ]
    }
]

提前感谢您的帮助。

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    有几种方法可以解决这个问题,但这在很大程度上取决于您的 MongoDB 版本。 2.6 及更高版本的最新版本支持 $map 运算符,您可以在 $project 中使用它来做您想做的事情:

    db.friend.aggregate([
        { "$project": {
            "name": 1,
            "buddies": {
                "$map": {
                    "input": "$friends",
                    "as": "el",
                    "in": {
                        "nickName": "$$el.name",
                        "age": "$$el.age"
                    }
                }
            }
        }}
    ])
    

    在以前的版本中,您将使用$unwind 处理数组元素并通过$group 重新构造:

    db.collection.aggregate([
        { "$unwind": "$friends" },
        { "$group": {
            "_id": "$_id",
            "name": { "$first": "$name" },
            "buddies": {
                "$push": {
                    "nickName": "$friends.name",
                    "age": "$friends.age"
                }
            }
        }}
    ])
    

    第一种形式效率更高一些,因为您不会对数组内容进行反规范化并在管道中生成更多要处理的文档。

    【讨论】:

    • 我在提交答案后才注意到您的答案。我目前使用的是 2.4 版,但真的很喜欢 2.6 版的 $map 运算符。您对 $unwind 和 group 的回答比我的简单,因为它不包括 $project。作为对其他人的确认,我刚刚使用 $unwind 和 $group 尝试了您的查询并且可以工作。
    • @BarDev 也更快,因为您实际上是在进行另一次遍历文档。另请注意,当您使用 $project“重命名”字段并包含现有字段时,无论您指定的顺序如何,都将始终首先列出现有字段。这是管道通过“复制”现有内容进行的一般优化。但是,$group 将保留您指定的顺序
    • 非常酷,很高兴知道。当谈到 MongoDB 时,我绝对是一个菜鸟,还有很多东西要学。感谢您的附加信息;这清楚地说明了事情是如何运作的。
    【解决方案2】:

    我想我想通了以下聚合查询。如果有更好的方法,我会很感兴趣。

    db.friends.aggregate([
        { $unwind: '$friends'},
        { $project: {
            _id: 1,
            name: 1,
            buddy: {
                nickName: '$friends.name',
                age: '$friends.age',
            }
        }},
        { $group: {        
            _id: '$_id',
            name: {'$first': '$name'},
            buddies: {"$push": "$buddy"}
        }}
    ]);
    

    下面我描述每个操作符($unwind、$project、$group)的响应

    $unwind 会返回类似这样的内容。它将每个嵌入式文档分解为自己的文档。所以我们有 1 个文档和 2 个朋友的子文档,现在我们有两个文档。两个文档将具有相同的 id 和 name 字段,但朋友子文档将不同:

    {
        "_id" : ObjectId("539c80d43cb9fe99d183a5f7"),
        "name" : "Matthew",
        "friends" : {"name" : "slim", "age" : "32"}
    }, {
        "_id" : : ObjectId("539c80d43cb9fe99d183a5f7"),,
        "name" : "Matthew",
        "friends" : {"name" : "buba", "age" : "36"}
    }
    

    $project 会返回类似这样的内容。在这里,我正在创建一个名为 buddy 的新嵌入式文档,并注意到我将“$friends.name”分配给“nickName”:

    {
        "_id" : ObjectId("539c80d43cb9fe99d183a5f7"),
        "name" : "Matthew",
        "buddy" : {"nickName" : "slim","age" : "32"}
    }, {
        "_id" : : ObjectId("539c80d43cb9fe99d183a5f7"),,
        "name" : "Matthew",
        "friends" : {"nickName" : "buba","age" : "36"}
    }
    

    然后 $group 会做这样的事情。在这里,我只是将所有内容重新组合在一起,但将数组名称设置为“buddies”:

    {
        "_id" : ObjectId("539c80d43cb9fe99d183a5f7"),
        "name" : "Matthew",
        "buddies" : [
            {"nickName" : "slim","age" : "32"},
            {"nickName" : "buba","age" : "36"}
        ]
    }
    

    这似乎可行,但如果朋友数组有重复项,此过程将删除重复项。如果每个朋友都有一个唯一的 id,就可以解决这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-26
      • 2021-07-27
      • 2021-10-24
      • 1970-01-01
      • 2011-05-15
      • 2023-03-30
      相关资源
      最近更新 更多