And*_*ore 25 mapreduce mongodb
更新:MongoDB的后续操作获取集合中所有键的名称.
正如Kristina所指出的,可以使用Mongodb的map/reduce来列出集合中的键:
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" ]
Run Code Online (Sandbox Code Playgroud)
只要我们想要只获得位于第一级深度的键,这就可以了.但是,它将无法检索位于更深层次的密钥.如果我们添加一条新记录:
db.things.insert({foo: {bar: {baaar: true}}})
Run Code Online (Sandbox Code Playgroud)
我们再次运行上面的map-reduce + distinct片段,我们将得到:
[ "_id", "egg", "foo", "hello", "type" ]
Run Code Online (Sandbox Code Playgroud)
但是我们不会得到数据结构中嵌套的bar和baaar键.问题是:如何检索所有密钥,无论其深度如何?理想情况下,我实际上希望脚本向下走到所有深度,产生如下输出:
["_id","egg","foo","foo.bar","foo.bar.baaar","hello","type"]
Run Code Online (Sandbox Code Playgroud)
先感谢您!
Gat*_* VP 27
好的,这有点复杂,因为你需要使用一些递归.
要使递归发生,您需要能够在服务器上存储一些函数.
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 } );
Run Code Online (Sandbox Code Playgroud)
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; }
Run Code Online (Sandbox Code Playgroud)
mr = db.runCommand({"mapreduce" : "things", "map" : map, "reduce" : reduce,"out": "things" + "_keys"});
db[mr.result].distinct("_id");
Run Code Online (Sandbox Code Playgroud)
您将获得的结果是:
["_id", "_id.isObjectId", "_id.str", "_id.tojson", "egg", "egg.0", "foo", "foo.bar", "foo.bar.baaaar", "hello", "type", "type.0", "type.1"]
Run Code Online (Sandbox Code Playgroud)
这里有一个明显的问题,我们在这里添加一些意想不到的字段:1._id数据2. .0(关于鸡蛋和类型)
对于问题#1,修复相对容易.只需修改map功能.改变这个:
emit(base + "." + key, null); if( isArray...
Run Code Online (Sandbox Code Playgroud)
对此:
if(key != "_id") { emit(base + "." + key, null); if( isArray... }
Run Code Online (Sandbox Code Playgroud)
问题#2有点冒险.你想要所有的键,技术上"egg.0" 是一个有效的键.您可以修改m_sub以忽略此类数字键.但是,这种情况也很容易让人感到厌恶.假设您在常规数组中有一个关联数组,那么您希望显示"0".我会把剩下的解决方案留给你.
小智 7
以盖茨副总裁和克里斯蒂娜的答案为灵感,我创建了一个名为Variety的开源工具,它正是这样做的:https://github.com/variety/variety
希望你会发现它很有用.如果您有任何问题或使用它有任何问题,请告诉我.