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

查看:29
本文介绍了使用 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" ] 

但是我们不会得到 barbaaar 键,它们嵌套在数据结构中.问题是:我如何检索所有密钥,无论它们的深度级别如何?理想情况下,我实际上希望脚本能够深入到所有级别的深度,产生如下输出:

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和reduce函数

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 步:运行 map 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 有点冒险.你想要所有键,技术上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天全站免登陆