使用map/reduce映射集合中的属性 [英] Using map/reduce for mapping the properties in a collection

查看:65
本文介绍了使用map/reduce映射集合中的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:的后续操作> MongoDB获取集合中所有键的名称.

Kristina 所指出的,人们可以使用Mongodb的map/reduce列出集合中的键:

As pointed out by Kristina, one can use Mongodb 's map/reduce to list the keys in a collection:

db.things.insert( { type : ['dog', 'cat'] } );
db.things.insert( { egg : ['cat'] } );
db.things.insert( { type :  [] }); 
db.things.insert( { hello : []  } );

mr = db.runCommand({"mapreduce" : "things",
"map" : function() {
    for (var key in this) { emit(key, null); }
},  
"reduce" : function(key, stuff) { 
   return null;
}}) 

db[mr.result].distinct("_id")

//output: [ "_id", "egg", "hello", "type" ]

只要我们只想获取位于第一深度级别的键,就可以正常工作.但是,它将无法检索位于更深层次的那些密钥.如果我们添加新记录:

As long as we want to get only the keys located at the first level of depth, this works fine. However, it will fail retrieving those keys that are located at deeper levels. If we add a new record:

db.things.insert({foo: {bar: {baaar: true}}})

然后再次运行上面的map-reduce + distinct代码段,我们将得到:

And we run again the map-reduce +distinct snippet above, we will get:

[ "_id", "egg", "foo", "hello", "type" ] 

但是我们不会获得嵌套在数据结构中的 bar baaar 键.问题是:无论深度如何,如何检索所有密钥?理想情况下,我实际上希望脚本深入到各个层次,并产生如下输出:

But we will not get the bar and the baaar keys, which are nested down in the data structure. The question is: how do I retrieve all keys, no matter their level of depth? Ideally, I would actually like the script to walk down to all level of depth, producing an output such as:

["_id","egg","foo","foo.bar","foo.bar.baaar","hello","type"]      

提前谢谢!

推荐答案

好的,这有点复杂,因为您需要使用一些递归.

OK, this is a little more complex because you'll need to use some recursion.

要进行递归,您需要能够在服务器上存储一些功能.

To make the recursion happen, you'll need to be able to store some functions on the server.

isArray = function (v) {
  return v && typeof v === 'object' && typeof v.length === 'number' && !(v.propertyIsEnumerable('length'));
}

m_sub = function(base, value){
  for(var key in value) {
    emit(base + "." + key, null);
    if( isArray(value[key]) || typeof value[key] == 'object'){
      m_sub(base + "." + key, value[key]);
    }
  }
}

db.system.js.save( { _id : "isArray", value : isArray } );
db.system.js.save( { _id : "m_sub", value : m_sub } );

步骤2:定义地图并简化功能

map = function(){
  for(var key in this) {
    emit(key, null);
    if( isArray(this[key]) || typeof this[key] == 'object'){
      m_sub(key, this[key]);
    }
  }
}

reduce = function(key, stuff){ return null; }

步骤3:运行地图reduce并查看结果

mr = db.runCommand({"mapreduce" : "things", "map" : map, "reduce" : reduce,"out": "things" + "_keys"});
db[mr.result].distinct("_id");

您将获得的结果是:

["_id", "_id.isObjectId", "_id.str", "_id.tojson", "egg", "egg.0", "foo", "foo.bar", "foo.bar.baaaar", "hello", "type", "type.0", "type.1"]

这里有一个明显的问题,我们在这里添加一些意外的字段: 1. _id数据 2. .0(关于鸡蛋和类型)

There's one obvious problem here, we're adding some unexpected fields here: 1. the _id data 2. the .0 (on egg and type)

对于问题1 ,修复相对容易.只需修改map函数.更改此:

For problem #1 the fix is relatively easy. Just modify the map function. Change this:

emit(base + "." + key, null); if( isArray...

对此:

if(key != "_id") { emit(base + "." + key, null); if( isArray... }

问题2 有点麻烦.您需要 all 键,从技术上讲,"egg.0" 是有效的键.您可以修改m_sub以忽略此类数字键.但是,也很容易看到这种事与愿违的情况.假设您在常规数组中有一个关联数组,那么您希望该"0"出现.我会将其余解决方案留给您.

Problem #2 is a little more dicey. You wanted all keys and technically "egg.0" is a valid key. You can modify m_sub to ignore such numeric keys. But it's also easy to see a situation where this backfires. Say you have an associative array inside of a regular array, then you want that "0" to appear. I'll leave the rest of that solution up to you.

这篇关于使用map/reduce映射集合中的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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