首页 文章

获取集合中所有键的名称

提问于
浏览
274

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

例如,从这个:

db.things.insert( { type : ['dog', 'cat'] } );
db.things.insert( { egg : ['cat'] } );
db.things.insert( { type : [] } );
db.things.insert( { hello : []  } );

我想得到独特的钥匙:

type, egg, hello

18 回答

  • -1

    使用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', ... ]
    
  • 185

    您可以使用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", ...]
    
  • 1

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

  • 23

    您可以使用3.4.4版本中的新$objectToArrray聚合将所有顶部键和值对转换为文档数组,然后将$unwind$group转换为$addToSet以在整个集合中获取不同的键 .

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

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

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

    db.things.aggregate([
      {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
      {"$project":{"keys":"$arrayofkeyvalue.k"}}
    ])
    
  • 7

    试试这个:

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

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

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

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

    以下是在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']
    
  • 1

    如果您使用的是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" }
      }}
    ])
    

    这是工作example

  • 1

    这对我来说很好:

    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);
    }
    
  • 1

    要获取所有键的列表减去 _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"];
    
  • 300

    我认为最好的方法是如上所述here在mongod 3.4.4中,但不使用 $unwind 运算符并且只使用管道中的两个阶段 . 相反,我们可以使用$mergeObjects$objectToArray运算符 .

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

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

    let allTopLevelKeys =  [
        {
            "$group": {
                "_id": null,
                "array": {
                    "$mergeObjects": "$$ROOT"
                }
            }
        },
        {
            "$project": {
                "keys": {
                    "$map": {
                        "input": { "$objectToArray": "$array" },
                        "in": "$$this.k"
                    }
                }
            }
        }
    ];
    

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

    {field1: {field2: "abc"}, field3: "def"}
    {field1: {field3: "abc"}, field4: "def"}
    

    以下管道产生所有键(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"
                            }
                        }
                    ]
                }
            }
        }
    ]
    

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

  • 13

    我试图在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');
            });
     });
    

    读取新创建的集合“allFieldNames”后,将其删除 .

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

    根据mongoldb documentationdistinct 的组合

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

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

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

    所以在给定的方法中,可以使用类似下面的方法,以便查询集合中所有已注册的索引,并返回,例如带有键索引的对象(此示例使用async / await作为NodeJS,但是显然你可以使用任何其他异步方法):

    async function GetFor(collection, index) {
    
        let currentIndexes;
        let indexNames = [];
        let final = {};
        let vals = [];
    
        try {
            currentIndexes = await collection.indexes();
            await ParseIndexes();
            //Check if a specific index was queried, otherwise, iterate for all existing indexes
            if (index && typeof index === "string") return await ParseFor(index, indexNames);
            await ParseDoc(indexNames);
            await Promise.all(vals);
            return final;
        } catch (e) {
            throw e;
        }
    
        function ParseIndexes() {
            return new Promise(function (result) {
                let err;
                for (let ind in currentIndexes) {
                    let index = currentIndexes[ind];
                    if (!index) {
                        err = "No Key For Index "+index; break;
                    }
                    let Name = Object.keys(index.key);
                    if (Name.length === 0) {
                        err = "No Name For Index"; break;
                    }
                    indexNames.push(Name[0]);
                }
                return result(err ? Promise.reject(err) : Promise.resolve());
            })
        }
    
        async function ParseFor(index, inDoc) {
            if (inDoc.indexOf(index) === -1) throw "No Such Index In Collection";
            try {
                await DistinctFor(index);
                return final;
            } catch (e) {
                throw e
            }
        }
        function ParseDoc(doc) {
            return new Promise(function (result) {
                let err;
                for (let index in doc) {
                    let key = doc[index];
                    if (!key) {
                        err = "No Key For Index "+index; break;
                    }
                    vals.push(new Promise(function (pushed) {
                        DistinctFor(key)
                            .then(pushed)
                            .catch(function (err) {
                                return pushed(Promise.resolve());
                            })
                    }))
                }
                return result(err ? Promise.reject(err) : Promise.resolve());
            })
        }
    
        async function DistinctFor(key) {
            if (!key) throw "Key Is Undefined";
            try {
                final[key] = await collection.distinct(key);
            } catch (e) {
                final[key] = 'failed';
                throw e;
            }
        }
    }
    

    因此,使用基本 _id 索引查询集合将返回以下内容(测试集合在测试时只有一个文档):

    Mongo.MongoClient.connect(url, function (err, client) {
        assert.equal(null, err);
    
        let collection = client.db('my db').collection('the targeted collection');
    
        GetFor(collection, '_id')
            .then(function () {
                //returns
                // { _id: [ 5ae901e77e322342de1fb701 ] }
            })
            .catch(function (err) {
                //manage your error..
            })
    });
    

    请注意,这使用了NodeJS驱动程序的原生方法 . 正如其他一些答案所暗示的那样,还有其他方法,例如聚合框架 . 我个人认为这种方法更灵活,因为您可以轻松创建和微调如何返回结果 . 显然,这只能解决顶级属性,而不是嵌套属性 . 此外,为了保证所有文档都被表示,如果存在二级索引(主_id除外),则应将这些索引设置为 required .

  • -4

    也许稍微偏离主题,但你可以递归地漂亮打印对象的所有键/字段:

    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)
    }
    

    当集合中的所有对象具有相同的结构时很有用 .

  • 0

    我对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;
            }
        }
    }
    

    跑:

    schemafy(db.collection.findOne());
    

    产量

    _id <number>
    id <number>
    t <string>
    p <number>
    ls <object>:
        0 <object>:
        l <string>
        p <object>:
            pp <number>
    
  • 0

    我有一个更简单的工作...

    你可以做的就是将数据/文档插入主集合“事物”必须在1个单独的集合中插入属性,让我们说“things_attributes” .

    因此,每次插入“things”时,您都会从“things_attributes”获得该文档的值与新文档键的比较,如果有任何新键将其附加到该文档中并再次重新插入它 .

    所以things_attributes将只有1个唯一键文档,您可以通过使用findOne()在需要时轻松获取这些文档

  • 2
    var schematodo = db.[collection].findOne();
    for (var key in schematodo) { print (key) ; }
    

相关问题