Mongo DB MapReduce:根据条件从数组中发出键

pes*_*ira 2 performance mapreduce mongodb

我是mongo db的新手,请原谅我,如果这是相当微不足道的话.我真的很感激帮助.

想法是生成一些特定值的直方图.在那种情况下,某些文件的mime类型.为此,我正在使用地图减少工作.

我有一个mongo文件,格式如下:

{
    "_id" : ObjectId("4fc5ed3e67960de6794dd21c"),
    "name" : "some name",
    "uid" : "some app specific uid",
    "collection" : "some name",
    "metadata" : [
        {
            "key" : "key1",
            "value" : "Plain text",
            "status" : "SINGLE_RESULT",
        },
        {
            "key" : "key2",
            "value" : "text/plain",
            "status" : "SINGLE_RESULT",
        },
        {
            "key" : "key3",
            "value" : 3469,
            "status" : "OK",
        }
     ]
}
Run Code Online (Sandbox Code Playgroud)

请注意,几乎每个文档中都有更多元数据键值.

地图减少工作

我尝试过以下操作:

function map() {
   var mime = "";
   this.metadata.forEach(function (m) {
     if (m.key === "key2") {
        mime = m.value;}
     });
     emit(mime, {count:1});
}

function reduce() {
  var res = {count:0};
  values.forEach(function (v) {res.count += v.count;});
  return res;
}

db.collection.mapReduce(map, reduce, {out: { inline : 1}})
Run Code Online (Sandbox Code Playgroud)

这似乎适用于少量文档(~15K),但问题是在映射阶段迭代所有元数据键值需要花费大量时间.在更多文档(〜1Mio)上运行此操作时,操作将持续进行.

所以我的问题是:有没有什么方法可以直接发出mime类型(值)而不是遍历所有键并选择它?或者是否有更好的方法来编写地图缩减功能.

像emit这样的东西(this.metadata.value {$ where this.metadata.key:"key2"})或者类似的......

谢谢你的帮助!

dam*_*ier 6

两个想法......

首先想到的是:你对这个文档架构的依恋程度如何?您是否可以将元数据字段值作为嵌入式文档而不是嵌入式数组,如下所示:

{
    "_id" : ObjectId("4fc5ed3e67960de6794dd21c"),
    "name" : "some name",
    "uid" : "some app specific uid",
    "collection" : "some name",
    "metadata" : {
        "key1" : {
            "value" : "Plain text",
            "status" : "SINGLE_RESULT"
        },
        "key2": {
            "value" : "text/plain",
            "status" : "SINGLE_RESULT"
        }, 
        "key3" : {
            "value" : 3469,
            "status" : "OK"
        }
     }
}
Run Code Online (Sandbox Code Playgroud)

然后你的地图步骤完全取消了循环:

function map() {
   emit( this.metadata["key2"].value, { count : 1 } );
}
Run Code Online (Sandbox Code Playgroud)

此时,您甚至可以将其转换为"组"命令而不是"mapReduce".

第二个想法:如果没有这样的模式更改,特别是如果"key2"出现在元数据数组的早期,那么一旦发现密钥可以保存自己的一些迭代,你至少可以急切地退出循环,如下所示:

function map() {
   var mime = "";
   this.metadata.forEach(function (m) {
     if (m.key === "key2") {
        mime = m.value;
        break;
     } 
     });
     emit(mime, {count:1});
}
Run Code Online (Sandbox Code Playgroud)

不确定任何一条路径是否是胜利的关键,但希望有用的想法.祝你好运!