在MongoDB中展平嵌套对象并重命名 [英] Flatten a nested object in MongoDB and rename

查看:109
本文介绍了在MongoDB中展平嵌套对象并重命名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有这样的文档

{
    "id" : "1415166669",
    "color" : {
        "14" : "Silver"
    },
    "name":"Random Name"
}

可以更改内部颜色的键,即下一个文档可能看起来像这样

where the key inside color can change, i.e Next Document may look like this

{
    "id" : "1415126969",
    "color" : {
        "11" : "Gold"
    },
    "name":"Random Name 2"
}

我想展平并重命名它们,以便我的文档具有如下相似的结构:

I want to flatten and rename them so that my documents have a similar structure as follows:

{
    "id" : "1415126969",
    "color"  : "Gold"
    "name":"Random Name 2"
}

{
    "id" : "1415166669",
    "color" : "Silver"
    "name":"Random Name"
}

我尝试使用聚合管道,但不确定如何继续进行. 任何人也可以建议使用Robomongo的方法,那也很好.

I tried using the aggregation pipeline but I am not sure how to proceed further. Also can anyone suggest a way using Robomongo, that would be nice as well.

推荐答案

为此,我将运行一个简单的JavaScript循环,因为它将很快且容易编写代码.也可以将其应用于相同的集合:

I would run a simple JavaScript loop for this, since it's going to be quite quick and easy to code. It can also be applied to the same collection:

var ops = [];

db.collection.find().forEach(function(doc) {
  let color;
  Object.keys(doc.color).forEach(function(key) {
    color = doc.color[key];
  });
  ops = [
    ...ops,
    { "updateOne": {
      "filter": { "_id": doc._id },
      "update": { "$set": { "color": color } }
    }}
  ];
  if ( ops.length >= 500 ) {
    db.collection.bulkWrite(ops);
     ops = [];
  }
})

if ( ops.length > 0 ) {
  db.collection.bulkWrite(ops);
   ops = [];
}

因此,您基本上遍历了对象的键"并获得了值,随后我们使用

So you basically traverse the "keys" of the object and get the value, which later we write back to the document with $set

或者,从MongoDB 3.4开始,您可以使用$objectToArray运行聚合语句以访问密钥.但是,您实际上仅应在集合包含数百万个文档的情况下执行此操作. $out 的要求意味着结果在新集合中,而不是当前的更新:

Alternately, since MongoDB 3.4 you can run an aggregation statement using $objectToArray in order to access the keys. But you really only should do this where the collection has millions of documents. The requirements of $out means the result is in new collection, and not the current one being updated:

db.collecion.aggregate([
  { "$addFields": {
    "color": {
     "$arrayElemAt": [
       { "$map": {
         "input": { "$objectToArray": "$color" },
         "as": "c",
         "in": "$$c.v"
       }},
       0
     ]
    }
  }},
  { "$out": "newcollection" }
])

之所以有效,是因为$objectToArray将您的结构变成这样:

This works because $objectToArray turns your structure like this:

"color": { "11": "Gold" }

对此:

"color": [{ "k": "11", "v": "Gold" }]

因此我们可以在 $map 运算符中使用为了提取"color.v"路径值和 $arrayElemAt 将其转换为奇异值而不是数组.

So we can then use the $map operator in order to extract the "color.v" path value and $arrayElemAt to turn this into a singular value rather than an array.

通常来说,对于聚合管道语句而言,这种转换要比通过简单地在代码中操纵文档结构然后写回目标集合所能实现的转换要复杂得多.

Generally speaking such conversions would be a lot more complex for aggregation pipeline statements than for what you can achieve simply by manipulating the document structure in code and then writing back to the target collection.

给出现有文件:

{
        "_id" : ObjectId("59389951fc04695e84e7f4ae"),
        "id" : "1415166669",
        "color" : {
                "14" : "Silver"
        },
        "name" : "Random Name"
}
{
        "_id" : ObjectId("59389a75fc04695e84e7f4af"),
        "id" : "1415126969",
        "color" : {
                "11" : "Gold"
        },
        "name" : "Random Name 2"
}

两种方法的输出是:

{
        "_id" : ObjectId("59389951fc04695e84e7f4ae"),
        "id" : "1415166669",
        "color" : "Silver",
        "name" : "Random Name"
}
{
        "_id" : ObjectId("59389a75fc04695e84e7f4af"),
        "id" : "1415126969",
        "color" : "Gold",
        "name" : "Random Name 2"
}

这篇关于在MongoDB中展平嵌套对象并重命名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆