我想获得MongoDB集合中所有键的名称。

例如,从这个:

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

我想获得唯一的键:

type, egg, hello

当前回答

沿着@James Cropcho的回答,我找到了下面这个我觉得超级好用的方法。这是一个二进制工具,这正是我正在寻找的: mongoeye。

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

其他回答

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

mongodb——host 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

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

我认为这里提到的最好的方法是在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"
                        }
                    }
                ]
            }
        }
    }
]

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

根据mongoldb文档,一个不同的组合

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

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

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

所以在一个给定的方法中,你可以使用下面的方法,为了查询一个集合中所有注册的索引,并返回一个对象,比如一个键的索引(这个例子使用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 Driver原生的方法。正如其他一些答案所建议的那样,还有其他方法,例如聚合框架。我个人认为这种方法更灵活,因为您可以轻松地创建和微调如何返回结果。显然,这只处理顶级属性,而不是嵌套属性。 此外,为了保证所有文档都被表示,如果有二级索引(除了主_id索引),这些索引应该根据需要设置。

沿着@James Cropcho的回答,我找到了下面这个我觉得超级好用的方法。这是一个二进制工具,这正是我正在寻找的: mongoeye。

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