获取集合中所有键的名称

Ste*_*eve 301 mongodb mongodb-query aggregation-framework

我想获取MongoDB集合中所有键的名称.

例如,从这个:

db.things.insert( { type : ['dog', 'cat'] } );
db.things.insert( { egg : ['cat'] } );
db.things.insert( { type : [] } );
db.things.insert( { hello : []  } );
Run Code Online (Sandbox Code Playgroud)

我想得到独特的钥匙:

type, egg, hello
Run Code Online (Sandbox Code Playgroud)

kri*_*ina 323

您可以使用MapReduce执行此操作:

mr = db.runCommand({
  "mapreduce" : "my_collection",
  "map" : function() {
    for (var key in this) { emit(key, null); }
  },
  "reduce" : function(key, stuff) { return null; }, 
  "out": "my_collection" + "_keys"
})
Run Code Online (Sandbox Code Playgroud)

然后在生成的集合上运行distinct,以便找到所有键:

db[mr.result].distinct("_id")
["foo", "bar", "baz", "_id", ...]
Run Code Online (Sandbox Code Playgroud)

  • 这可能是显而易见的,但是如果你想得到一个子文档中所有唯一键的列表,只需修改这一行:`for(var key in this.first_level.second_level.nth_level){emit(key,null); }` (6认同)
  • 我知道这是一个老线程,但我似乎有类似的需求.我正在使用nodejs mongodb本机驱动程序.由此产生的临时收集似乎总是空着.我正在集合类中使用mapreduce函数.这不可能吗? (3认同)
  • 我没有保存到集合然后运行不同的集合,而是使用 map(): `db.runCommand({..., out: { "inline" : 1 }}).results.map(function(i) { return i._id; });` (3认同)
  • 嗨,您好!我刚刚发布了一个关于这个问题的后续问题,询问如何使这个代码片段工作,即使是位于数据结构更深层次的密钥(http://stackoverflow.com/questions/2997004/using-map-reduce-for -mapping最性质-IN-A-集合). (2认同)

小智 196

Kristina的答案为灵感,我创建了一个名为Variety的开源工具,它正是这样做的:https://github.com/variety/variety

  • 祝贺,这是一个很棒的工具.它完全符合问题的要求,并且可以配置限制,深度等.任何跟随的人推荐. (13认同)

use*_*814 52

您可以使用聚集新$objectToArrray3.4.4版本所有顶级密钥值对转换成文件阵列,然后$unwind$group $addToSet得到跨越整个集合不同的键.

$$ROOT 用于引用顶级文档.

db.things.aggregate([
  {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
  {"$unwind":"$arrayofkeyvalue"},
  {"$group":{"_id":null,"allkeys":{"$addToSet":"$arrayofkeyvalue.k"}}}
])
Run Code Online (Sandbox Code Playgroud)

您可以使用以下查询来获取单个文档中的键.

db.things.aggregate([
  {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
  {"$project":{"keys":"$arrayofkeyvalue.k"}}
])
Run Code Online (Sandbox Code Playgroud)

  • 这真是最好的答案.在不涉及其他编程语言或包的情况下解决问题,并与支持聚合框架的所有驱动程序一起使用(甚至是Meteor!) (14认同)
  • 如果您想返回一个数组而不是包含带有“allkeys”键的单个映射条目的游标,您可以将 `.next()["allkeys"]` 附加到命令中(假设集合至少有一个元素) 。 (2认同)

小智 19

试试这个:

doc=db.thinks.findOne();
for (key in doc) print(key);
Run Code Online (Sandbox Code Playgroud)

  • 不正确的答案,因为这只输出集合中单个文档的字段 - 其他可能都有完全不同的键. (45认同)
  • 对我来说它仍然是最有用的答案,是一个简单的合理最小值. (14认同)
  • 它没用吗?如果它给你错误的答案,它是如何有用的? (11认同)
  • 这不是一个好的答案它是如何获得集合中****元素的键而不是集合中的所有**键的答案! (5认同)
  • 上下文显示了什么是有用的:如果数据被规范化(例如来自CSV文件的origen),它是有用的......对于从SQL导入的数据是有用的. (4认同)
  • 这将解决像`db.thinks.find().forEach(function(doc){for(key in doc)print(key);}); (3认同)
  • 我认为这个答案对这个问题不起作用,但它确实解决了我的问题:在文档中查找密钥。+1 (2认同)

小智 14

如果您的目标集合不是太大,您可以在mongo shell客户端下尝试:

var allKeys = {};

db.YOURCOLLECTION.find().forEach(function(doc){Object.keys(doc).forEach(function(key){allKeys[key]=1})});

allKeys;
Run Code Online (Sandbox Code Playgroud)


Lai*_*zer 9

使用python.返回集合中所有顶级键的集合:

#Using pymongo and connection named 'db'

reduce(
    lambda all_keys, rec_keys: all_keys | set(rec_keys), 
    map(lambda d: d.keys(), db.things.find()), 
    set()
)
Run Code Online (Sandbox Code Playgroud)

  • 我确信与直接在 Mongodb 中执行此操作相比,这是极其低效的 (2认同)

Ing*_*her 9

使用pymongo清理并重用的解决方案:

from pymongo import MongoClient
from bson import Code

def get_keys(db, collection):
    client = MongoClient()
    db = client[db]
    map = Code("function() { for (var key in this) { emit(key, null); } }")
    reduce = Code("function(key, stuff) { return null; }")
    result = db[collection].map_reduce(map, reduce, "myresults")
    return result.distinct('_id')
Run Code Online (Sandbox Code Playgroud)

用法:

get_keys('dbname', 'collection')
>> ['key1', 'key2', ... ]
Run Code Online (Sandbox Code Playgroud)

  • 效果很好。终于解决了我的问题...这是我在堆栈溢出中看到的最简单的解决方案.. (2认同)

Bob*_*bHy 8

以下是在Python中使用的示例:此示例以内联方式返回结果.

from pymongo import MongoClient
from bson.code import Code

mapper = Code("""
    function() {
                  for (var key in this) { emit(key, null); }
               }
""")
reducer = Code("""
    function(key, stuff) { return null; }
""")

distinctThingFields = db.things.map_reduce(mapper, reducer
    , out = {'inline' : 1}
    , full_response = True)
## do something with distinctThingFields['results']
Run Code Online (Sandbox Code Playgroud)


sty*_*ane 6

我认为这里提到的最好的方法是在 mongod 3.4.4+ 中,但不使用$unwind运算符并且只使用管道中的两个阶段。相反,我们可以使用$mergeObjectsand$objectToArray运算符。

$group阶段,我们使用$mergeObjects运算符返回单个文档,其中键/值来自集合中的所有文档。

然后是$project我们使用$map$objectToArray返回密钥的地方。

let allTopLevelKeys =  [
    {
        "$group": {
            "_id": null,
            "array": {
                "$mergeObjects": "$$ROOT"
            }
        }
    },
    {
        "$project": {
            "keys": {
                "$map": {
                    "input": { "$objectToArray": "$array" },
                    "in": "$$this.k"
                }
            }
        }
    }
];
Run Code Online (Sandbox Code Playgroud)

现在如果我们有一个嵌套的文档并且想要获取密钥,这是可行的。为简单起见,让我们考虑一个带有简单嵌入文档的文档,如下所示:

{field1: {field2: "abc"}, field3: "def"}
{field1: {field3: "abc"}, field4: "def"}
Run Code Online (Sandbox Code Playgroud)

以下管道产生所有键(field1、field2、field3、field4)。

let allFistSecondLevelKeys = [
    {
        "$group": {
            "_id": null,
            "array": {
                "$mergeObjects": "$$ROOT"
            }
        }
    },
    {
        "$project": {
            "keys": {
                "$setUnion": [
                    {
                        "$map": {
                            "input": {
                                "$reduce": {
                                    "input": {
                                        "$map": {
                                            "input": {
                                                "$objectToArray": "$array"
                                            },
                                            "in": {
                                                "$cond": [
                                                    {
                                                        "$eq": [
                                                            {
                                                                "$type": "$$this.v"
                                                            },
                                                            "object"
                                                        ]
                                                    },
                                                    {
                                                        "$objectToArray": "$$this.v"
                                                    },
                                                    [
                                                        "$$this"
                                                    ]
                                                ]
                                            }
                                        }
                                    },
                                    "initialValue": [

                                    ],
                                    "in": {
                                        "$concatArrays": [
                                            "$$this",
                                            "$$value"
                                        ]
                                    }
                                }
                            },
                            "in": "$$this.k"
                        }
                    }
                ]
            }
        }
    }
]
Run Code Online (Sandbox Code Playgroud)

只需稍加努力,我们就可以获得数组字段中所有子文档的键,其中元素也是对象。


Ash*_*shh 6

如果您使用的是mongodb 3.4.4及更高版本,则可以使用$objectToArray$group聚合来使用以下聚合

db.collection.aggregate([
  { "$project": {
    "data": { "$objectToArray": "$$ROOT" }
  }},
  { "$project": { "data": "$data.k" }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": null,
    "keys": { "$addToSet": "$data" }
  }}
])
Run Code Online (Sandbox Code Playgroud)

这是工作示例


kri*_*sad 6

我很惊讶,这里没有人通过使用简单javascriptSet逻辑来自动过滤重复值,mongo shell上的简单示例如下:

var allKeys = new Set()
db.collectionName.find().forEach( function (o) {for (key in o ) allKeys.add(key)})
for(let key of allKeys) print(key)
Run Code Online (Sandbox Code Playgroud)

这将打印集合名称中所有可能的唯一collectionName