Mongodb 获取集合中所有键的名称

Mongodb 获取集合中所有键的名称,mongodb,mongodb-query,aggregation-framework,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 : [] } ); 我想得到唯一的钥匙: type, egg, hello 可以使用MapReduce执行此操作: mr = db.ru

我想获得MongoDB集合中所有密钥的名称

例如,从以下方面:

db.things.insert( { type : ['dog', 'cat'] } );
db.things.insert( { egg : ['cat'] } );
db.things.insert( { type : [] } );
db.things.insert( { hello : []  } );
我想得到唯一的钥匙:

type, egg, hello

可以使用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"
})
然后在生成的集合上运行distinct以查找所有键:

db[mr.result].distinct("_id")
["foo", "bar", "baz", "_id", ...]
作为灵感,我创建了一个名为Variety的开源工具,它正是这样做的:

试试这个:

doc=db.thinks.findOne();
for (key in doc) print(key);

我有一个更简单的工作

您可以做的是,在将数据/文档插入主集合“things”时,必须在1个单独的集合中插入属性,例如“things\u attributes”

因此,每次插入“things”时,您都会从“things\u attributes”中获得将该文档的值与新文档键进行比较的信息(如果存在任何新键),请将其附加到该文档中,然后再次重新插入


因此,things_属性将只有一个唯一密钥的文档,您可以在需要时使用findOne()轻松获取该文档。

我对Carlos LM的解决方案进行了一些扩展,因此它更加详细

模式示例:

var schema = {
    _id: 123,
    id: 12,
    t: 'title',
    p: 4.5,
    ls: [{
            l: 'lemma',
            p: {
                pp: 8.9
            }
        },
         {
            l: 'lemma2',
            p: {
               pp: 8.3
           }
        }
    ]
};
在控制台中键入:

var schemafy = function(schema, i, limit) {
    var i = (typeof i !== 'undefined') ? i : 1;
    var limit = (typeof limit !== 'undefined') ? limit : false;
    var type = '';
    var array = false;

    for (key in schema) {
        type = typeof schema[key];
        array = (schema[key] instanceof Array) ? true : false;

        if (type === 'object') {
            print(Array(i).join('    ') + key+' <'+((array) ? 'array' : type)+'>:');
            schemafy(schema[key], i+1, array);
        } else {
            print(Array(i).join('    ') + key+' <'+type+'>');
        }

        if (limit) {
            break;
        }
    }
}
输出

_id <number>
id <number>
t <string>
p <number>
ls <object>:
    0 <object>:
    l <string>
    p <object>:
        pp <number> 
\u id
身份证件
T
P
ls:
0 :
L
p:
聚丙烯

以下是用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']

使用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()
)

这对我来说很好:

var arrayOfFieldNames = [];

var items = db.NAMECOLLECTION.find();

while(items.hasNext()) {
  var item = items.next();
  for(var index in item) {
    arrayOfFieldNames[index] = index;
   }
}

for (var index in arrayOfFieldNames) {
  print(index);
}

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

var allKeys = {};

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

allKeys;

您可以在版本中使用带有新聚合运算符的聚合将所有顶级键值对转换为文档数组,然后使用和在整个集合中获取不同的键。(用于引用顶级文档。)

您可以使用以下查询在单个文档中获取密钥

db.things.aggregate([
  {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
  {"$unwind":"$arrayofkeyvalue"},
  {"$group":{"_id":null,"allkeys":{"$addToSet":"$arrayofkeyvalue.k"}}}
])
db.things.aggregate([
  {"$match":{_id: "<<ID>>"}}, /* Replace with the document's ID */
  {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
  {"$project":{"keys":"$arrayofkeyvalue.k"}}
])
db.things.aggregate([
{“$match”:{{u id:”“}},/*替换为文档的id*/
{“$project”:{“arrayofkeyvalue”:{“$objectToArray”:“$$ROOT”}},
{“$project”:{“keys”:“$arrayofkeyvalue.k”}
])

我试着用nodejs编写代码,最后得出了以下结论:

db.collection('collectionName').mapReduce(
function() {
    for (var key in this) {
        emit(key, null);
    }
},
function(key, stuff) {
    return null;
}, {
    "out": "allFieldNames"
},
function(err, results) {
    var fields = db.collection('allFieldNames').distinct('_id');
    fields
        .then(function(data) {
            var finalData = {
                "status": "success",
                "fields": data
            };
            res.send(finalData);
            delteCollection(db, 'allFieldNames');
        })
        .catch(function(err) {
            res.send(err);
            delteCollection(db, 'allFieldNames');
        });
 });
读取新创建的集合“AllFieldName”后,将其删除

db.collection("allFieldNames").remove({}, function (err,result) {
     db.close();
     return; 
});

使用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')
用法:

get_keys('dbname', 'collection')
>> ['key1', 'key2', ... ]

获取所有键的列表减去<代码> { ID>代码>,请考虑运行下面的聚合管道:

var keys = db.collection.aggregate([
    { "$project": {
       "hashmaps": { "$objectToArray": "$$ROOT" } 
    } }, 
    { "$project": {
       "fields": "$hashmaps.k"
    } },
    { "$group": {
        "_id": null,
        "fields": { "$addToSet": "$fields" }
    } },
    { "$project": {
            "keys": {
                "$setDifference": [
                    {
                        "$reduce": {
                            "input": "$fields",
                            "initialValue": [],
                            "in": { "$setUnion" : ["$$value", "$$this"] }
                        }
                    },
                    ["_id"]
                ]
            }
        }
    }
]).toArray()[0]["keys"];

我认为最好的方法是在mongod 3.4.4+中,但不使用
$unwind
操作符,也不使用管道中的两个阶段。相反,我们可以使用and运算符

$group
阶段,我们使用
$mergeObjects
操作符返回单个文档,其中key/value来自集合中的所有文档

然后是
$project
,我们使用
$map
$objectToArray
返回键

let allTopLevelKeys =  [
    {
        "$group": {
            "_id": null,
            "array": {
                "$mergeObjects": "$$ROOT"
            }
        }
    },
    {
        "$project": {
            "keys": {
                "$map": {
                    "input": { "$objectToArray": "$array" },
                    "in": "$$this.k"
                }
            }
        }
    }
];
var map = new BsonJavaScript("function() { for (var key in this) { emit(key, null); } }");
var reduce = new BsonJavaScript("function(key, stuff) { return null; }");
var options = new MapReduceOptions<BsonDocument, BsonDocument>();
var result = await collection.MapReduceAsync(map, reduce, options);
var list = result.ToEnumerable().Select(item => item["_id"].ToString());

现在,如果我们有一个嵌套的文档,并且希望获得密钥,这是可行的。为了简单起见,让我们考虑一个具有简单嵌入文档的文档:
{field1: {field2: "abc"}, field3: "def"}
{field1: {field3: "abc"}, field4: "def"}
以下管道产生所有键(field1、field2、field3、field4)


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

根据mongoldb,一种不同的
distinct

在单个集合或视图中查找指定字段的不同值,并在数组中返回结果

和收集操作将返回给定键或索引的所有可能值:

返回一个数组,该数组包含标识和描述集合上现有索引的文档列表

因此,在给定的方法中,可以使用如下方法来查询集合中所有已注册的索引,并返回一个对象,比如索引为键的对象(本例使用async/Wait作为NodeJ,但显然可以使用任何其他异步方法):

因此,查询具有基本
\u id
索引的集合将返回以下内容(测试集合在测试时只有一个文档):

请注意,这将使用NodeJS驱动程序固有的方法。正如其他一些答案所表明的那样,还有其他方法,例如聚合框架。我个人认为这种方法更灵活,因为您可以轻松创建和微调返回结果的方式。显然,这只处理顶级属性,而不是嵌套属性。
此外,为了保证在有二级索引(主id索引除外)的情况下表示所有文档,应将这些索引设置为
必需

如果您使用的是mongodb 3.4.4及以上版本,则可以使用和聚合使用以下聚合

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

下面是工作

可能有点离题,但您可以递归地漂亮地打印对象的所有键/字段:

function _printFields(item, level) {
    if ((typeof item) != "object") {
        return
    }
    for (var index in item) {
        print(" ".repeat(level * 4) + index)
        if ((typeof item[index]) == "object") {
            _printFields(item[index], level + 1)
        }
    }
}

function printFields(item) {
    _printFields(item, 0)
}

当集合中的所有对象都具有相同结构时,此选项非常有用

我们可以通过使用mongo js文件来实现这一点。在您的getCollectionName.js文件中添加以下代码,并在Linux控制台中运行js文件,如下所示:

mongo——主机192.168.1.135 getCollectionName.js


谢谢@ackuser

我很惊讶,这里没有人通过使用简单的
javascript
Set
逻辑来自动过滤重复的值,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)

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

根据@James Cropcho的回答,我找到了以下我发现非常容易使用的主题。这是一个二进制工具,正是我想要的:


使用这个工具,从命令行导出我的模式大约需要2分钟。

我知道这个问题已经有10年了,但没有C#解决方案,我花了几个小时才弄清楚。我正在使用.NET驱动程序a
db.collection.aggregate([
  { "$project": {
    "data": { "$objectToArray": "$$ROOT" }
  }},
  { "$project": { "data": "$data.k" }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": null,
    "keys": { "$addToSet": "$data" }
  }}
])
function _printFields(item, level) {
    if ((typeof item) != "object") {
        return
    }
    for (var index in item) {
        print(" ".repeat(level * 4) + index)
        if ((typeof item[index]) == "object") {
            _printFields(item[index], level + 1)
        }
    }
}

function printFields(item) {
    _printFields(item, 0)
}
db_set = connect("192.168.1.135:27017/database_set_name"); // for Local testing
// db_set.auth("username_of_db", "password_of_db"); // if required

db_set.getMongo().setSlaveOk();

var collectionArray = db_set.getCollectionNames();

collectionArray.forEach(function(collectionName){

    if ( collectionName == 'system.indexes' || collectionName == 'system.profile' || collectionName == 'system.users' ) {
        return;
    }

    print("\nCollection Name = "+collectionName);
    print("All Fields :\n");

    var arrayOfFieldNames = []; 
    var items = db_set[collectionName].find();
    // var items = db_set[collectionName].find().sort({'_id':-1}).limit(100); // if you want fast & scan only last 100 records of each collection
    while(items.hasNext()) {
        var item = items.next(); 
        for(var index in item) {
            arrayOfFieldNames[index] = index;
        }
    }
    for (var index in arrayOfFieldNames) {
        print(index);
    }

});

quit();
var allKeys = new Set()
db.collectionName.find().forEach( function (o) {for (key in o ) allKeys.add(key)})
for(let key of allKeys) print(key)
var map = new BsonJavaScript("function() { for (var key in this) { emit(key, null); } }");
var reduce = new BsonJavaScript("function(key, stuff) { return null; }");
var options = new MapReduceOptions<BsonDocument, BsonDocument>();
var result = await collection.MapReduceAsync(map, reduce, options);
var list = result.ToEnumerable().Select(item => item["_id"].ToString());