在mongodb中转换集合的内存有效方法

时间:2016-01-24 18:15:22

标签: mongodb mapreduce mongodb-query aggregation-framework

我在mongodb中有这样的集合:

{
        "_id" : ObjectId("56a5f47ed420cf0db5b70242"),
        "tag" : "swift",
        "values" : [
                {
                        "word" : "osx",
                        "value" : 0.02
                },
                {
                        "word" : "compiler",
                        "value" : 0.01
                }
        ]
},
{
        "_id" : ObjectId("56a5f47ed420cf0db5b70243"),
        "tag" : "c++",
        "values" : [
                {
                        "word" : "namespace",
                        "value" : 0.04
                },
                {
                        "word" : "compiler",
                        "value" : 0.05
                }
        ]
}

我需要在集合中对其进行转换:

{
        "_id" : ObjectId("56a5f4e5d420cf0db5b70247"),
        "word" : "namespace",
        "values" : [
                {
                        "tag" : "c++",
                        "value" : 0.04
                }
        ]
},
{
        "_id" : ObjectId("56a5f4e5d420cf0db5b70248"),
        "word" : "compiler",
        "values" : [
                {
                        "tag" : "swift",
                        "value" : 0.01
                },
                {
                        "tag" : "c++",
                        "value" : 0.05
                }
        ]
},
{
        "_id" : ObjectId("56a5f4e5d420cf0db5b70249"),
        "word" : "osx",
        "values" : [
                {
                        "tag" : "swift",
                        "value" : 0.02
                }
        ]
}

我刚开始使用mongodb和MapReduce并且有一些问题:

  1. 在我的情况下,我应该使用带有$ out的MapReduce或Aggregation框架到另一个集合吗?
  2. 哪种方法更有效?因为一个集合很大(3gb)而我只有8GB的RAM,所以我害怕得到一个OutOfMemory错误。
  3. 如果我将使用MapReduce,那么map和reduce阶段应该是什么?我应该在地图阶段发出像{"word": word, "values": {"tag":tag, "value": value} }这样的项目并将其合并到reduce状态?

1 个答案:

答案 0 :(得分:3)

使用.aggregate()方法。

您需要使用$unwind运算符对“值”数组进行非规范化。管道中的最后一个阶段是$group阶段,您可以通过“values.word”对文档进行分组,并使用$push累加器运算符返回每个组的子文档数组。

从那里,您可以使用"bulk"操作将文档插入到新的集合中。

var bulk = db.myCollection.initializeOrderedBulkOp();
var count  = 0;
db.collection.aggregate( [ 
    { "$unwind": "$values" }, 
    { "$group": { 
        "_id": "$values.word", 
        "values": { 
             "$push": { "tag": "$tag", "value": "$values.value" } 
        } 
    } }
]).forEach(function(doc) { 
    bulk.insert( { "word": doc._id, "values": doc.values } );
    count++;
    if ( count % 1000 === 0 ) {
        // Execute per 1000 operations and re-init
        bulk.execute();
        bulk = db.myCollection.initializeOrderedBulkOp();
    }
});
// Clean up queues
if (count > 0 ) {
    bulk.execute();
}