代码之家  ›  专栏  ›  技术社区  ›  searain

一个集合中的MongoDB文档可以有不同的架构,但如何在一个集合中找到文档的所有架构?[副本]

  •  0
  • searain  · 技术社区  · 6 年前

    我想知道MongoDB集合中所有密钥的名称。

    例如,从这里:

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

    我想得到唯一的钥匙:

    type, egg, hello
    
    0 回复  |  直到 6 年前
        1
  •  332
  •   kris    10 年前

    您可以使用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", ...]
    
        2
  •  196
  •   Community pid    7 年前

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

        3
  •  55
  •   s7vr    6 年前

    可以将聚合与新的 $objectToArrray 在里面 3.4.4 $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"}}
    ])
    
        4
  •  19
  •   Jeff Loughlin    10 年前

    试试这个:

    doc=db.thinks.findOne();
    for (key in doc) print(key);
    
        5
  •  15
  •   Li Chunlin    8 年前

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

    var allKeys = {};
    
    db.YOURCOLLECTION.find().forEach(function(doc){Object.keys(doc).forEach(function(key){allKeys[key]=1})});
    
    allKeys;
    
        6
  •  10
  •   Wolkenarchitekt    5 年前

    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', ... ]
    
        7
  •  9
  •   Laizer    10 年前

    使用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()
    )
    
        8
  •  8
  •   BobHy    10 年前

    以下是在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']
    
        9
  •  6
  •   Ashh    6 年前

    $objectToArray $group

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

    这就是工作 example

        10
  •  3
  •   krishna Prasad    5 年前

    javascript Set 自动筛选重复值的逻辑,上的简单示例 蒙哥贝壳 如下所示:

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

    钥匙 在集合名称中: 收藏名称

        11
  •  2
  •   jimm101    8 年前

    这对我很有用:

    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);
    }
    
        12
  •  1
  •   chridam Gino Claudi    6 年前

    得到所有键的列表 _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"];
    
        13
  •  1
  •   Sede    6 年前

    我想最好的办法就是 here 在Mongod3.4.4+中,但不使用 $unwind $mergeObjects $objectToArray 操作员。

    $group 舞台,我们用 $合并对象

    然后是 $project $map 把钥匙还给我。

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

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

        14
  •  0
  •   Gautam    7 年前

    我试着用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; 
    });
    
        15
  •  0
  •   jlmurph    6 年前

    根据蒙古数据库 documentation ,一个组合 distinct

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

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

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

    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驱动程序本机的方法。正如其他一些答案所暗示的,还有其他方法,例如聚合框架。我个人认为这种方法更灵活,因为您可以轻松地创建和微调如何返回结果。显然,这只处理顶级属性,而不是嵌套属性。 此外,为了保证所有文档都有表示,如果有二级索引(主索引除外),这些索引应该设置为 required

        16
  •  0
  •   qed    6 年前

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

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

        17
  •  0
  •   Irshad Khan    6 年前

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

    mongo—主机192.168.1.135 getCollectionName.js

    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();
    

    谢谢@ackuser

        18
  •  0
  •   paneer_tikka    5 年前

    根据@James Cropcho的答案,我找到了一个非常容易使用的线索。它是一个二进制工具,这正是我想要的: mongoeye

    使用此工具从命令行导出我的架构大约需要2分钟。

        19
  •  -1
  •   va5ja    10 年前

    我把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> 
    
        20
  •  -3
  •   Paresh Behede    10 年前

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

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

    因此,things\u属性只有一个惟一密钥文档,您可以在任何需要时使用findOne()轻松获取该文档