Mongo将嵌入式文档转换为数组

时间:2016-03-22 20:39:13

标签: mongodb mongodb-query

有没有办法将嵌套文档结构转换为数组?以下是一个例子:

输入

"experience" : {
        "0" : {
            "duration" : "3 months",
            "end" : "August 2012",
            "organization" : {
                "0" : {
                    "name" : "Bank of China",
                    "profile_url" : "http://www.linkedin.com/company/13801"
                }
            },
            "start" : "June 2012",
            "title" : "Intern Analyst"
        }
    },

预期输出:

"experience" : [
           {
            "duration" : "3 months",
            "end" : "August 2012",
            "organization" : {
                "0" : {
                    "name" : "Bank of China",
                    "profile_url" : "http://www.linkedin.com/company/13801"
                }
            },
            "start" : "June 2012",
            "title" : "Intern Analyst"
        }
    ],

目前我正在使用脚本迭代每个元素,将它们转换为数组&最后更新文件。但这需要花费很多时间,有没有更好的方法呢?

3 个答案:

答案 0 :(得分:5)

您仍需要迭代内容,但您应该使用批量操作进行回写:

MongoDB 2.6及更高版本:

var bulk = db.collection.initializeUnorderedBulkOp(),
    count = 0;

db.collection.find({ 
   "$where": "return !Array.isArray(this.experience)"
}).forEach(function(doc) {
    bulk.find({ "_id": doc._id }).updateOne({
        "$set": { "experience": [doc.experience["0"]] }
    });
    count++;

    // Write once in 1000 entries
    if ( count % 1000 == 0 ) {
        bulk.execute();    
        bulk = db.collection.initializeUnorderedBulkOp();
    }
})

// Write the remaining
if ( count % 1000 != 0 )
    bulk.execute();

或者在MongoDB 3.2及更高版本的现代版本中,首选bulkWrite()方法:

var ops = [];

db.collection.find({ 
   "$where": "return !Array.isArray(this.experience)"
}).forEach(function(doc) {
   ops.push({
       "updateOne": {
           "filter": { "_id": doc._id },
           "update": { "$set": { "experience": [doc.experience["0"]] } }
       }
   });

   if ( ops.length == 1000 ) {
       db.collection.bulkWrite(ops,{ "ordered": false })
       ops = [];
   }
})

if ( ops.length > 0 )
    db.collection.bulkWrite(ops,{ "ordered": false });

因此,当通过游标写回数据库时,使用"无序"进行批量写入操作。设置是要走的路。它是每批1000个请求中只有一个写/响应,这减少了很多开销,并且#34;无序"意味着写入可以并行发生,而不是按顺序发生。这一切都使它更快。

答案 1 :(得分:0)

查看此查询是否适用于您的MongoDB版本

对于MongoDB版本3.2 +:

db.doc.aggregate([
    {$project:{experience:["$experience.0"]}}
])

MongoDB< 3.2:

db.doc.aggregate([
    {$group: {_id:"$_id", experience:{$push:"$experience.0"}}}
])

它应该将您的文档转换为:

{ 
    "_id" : ObjectId("56f1b046a65ea8a72c34839c"), 
    "experience" : [
        {
            "duration" : "3 months", 
            "end" : "August 2012", 
            "organization" : {
                "0" : {
                    "name" : "Bank of China", 
                    "profile_url" : "http://www.linkedin.com/company/13801"
                }
            }, 
            "start" : "June 2012", 
            "title" : "Intern Analyst"
        }
    ]
}

如果您想使用聚合框架永久地更改集合中的文档,那么这是一种更好的方法。

假设您的收藏集名称为doc

db.doc.aggregate([
    {$group: {_id:"$_id", experience:{$push:"$experience.0"}}},
    {$out: "doc"}
])

上面的查询将转换所有文档。

答案 2 :(得分:0)

对于mongoDB版本> 4.2:

db.doc.aggregate([{ $match: {'experience.0': { $exists: false } } },
    {$project:{experience:["$experience.0"]}}, { $merge: { into: "doc", on: "_id" }
])

注意::这里我们将更新的字段/文档与现有文档合并,但不替换/更新整个文档,$merge的默认行为是merge 找到匹配的文档后,您可以传递其他选项,例如replace / keepExisting等。

参考: $merge