Update:次随访至MongoDB Get names of all keys in collection次.

正如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" ]

只要我们只想得到位于第一层深度的关键点,这就行了.然而,它将无法检索位于更深层次的密钥.如果我们添加新记录:

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

我们再次运行上面的map reduce+distinct片段,我们将得到:

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

但我们不会得到嵌套在数据 struct 中的barbaaar键.问题是:如何检索所有键,无论其深度如何?理想情况下,我希望脚本能够深入到各个层次,产生如下输出:

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

提前谢谢!

推荐答案

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

要实现递归,需要能够在服务器上存储一些函数.

第一步:定义一些函数并将它们放在服务器端

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"]

这里有一个明显的问题,我们在这里添加了一些意想不到的字段:

第4步:一些可能的修复

对于problem #1来说,修复相对容易.只需修改map函数.改变这一点:

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

为此:

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

Problem #2有点冒险.你想要all把 keys ,从技术上讲,"egg.0"is是一把有效的 keys .您可以修改m_sub以忽略此类数字键.但也很容易看到事与愿违的情况.假设你在一个常规数组中有一个关联数组,那么你希望这个"0"出现.剩下的问题就交给你了.

Mongodb相关问答推荐

使用MongoDB 4将根文档替换为数组

在MongoDB集合中按文档内的频率对数组排序

如何获取键值对的对象,其中值仅具有 mongoDB 中的投影字段

随着时间的推移在 mongodb 中获得

Mongodb聚合中基于其他字段值的多个条件的动态新字段值

MongoDB乘以对象值?

Mongoose $inc 枚举验证失败

mongoose中的 required是什么意思?

MongoDB - 如果新值更大,则更新字段

为什么 local.oplog.rs 上每隔几分钟的活动就会锁定 mongo 客户端

.save() 不是函数 Mongoose

Node.js MongoDB Upsert 更新

如何在我的Meteor 应用程序数据库中使用 mongoimport?

MongoDB:查询和检索嵌入式数组中的对象?

MongoDB如何判断是否存在

通过 Java 执行 Mongo like Query (JSON)

我在更新中对 $set 和 $inc 做错了什么

通过浏览器连接mongodb?

我如何将 mongodb 与electron一起使用?

在 mongodb 集合中查找最旧/最新的帖子