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

例如,从这个:

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

我想获得唯一的键:

type, egg, hello

当前回答

要获得所有键减去_id的列表,可以考虑运行以下聚合管道:

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

其他回答

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

我知道我来晚了,但如果你想在python中快速找到所有键(甚至嵌套的键),你可以用递归函数来做:

def get_keys(dl, keys=None):
    keys = keys or []
    if isinstance(dl, dict):
        keys += dl.keys()
        list(map(lambda x: get_keys(x, keys), dl.values()))
    elif isinstance(dl, list):
        list(map(lambda x: get_keys(x, keys), dl))
    return list(set(keys))

像这样使用它:

dl = db.things.find_one({})
get_keys(dl)

如果你的文件没有相同的密钥,你可以这样做:

dl = db.things.find({})
list(set(list(map(get_keys, dl))[0]))

但是这个解决方案肯定是可以优化的。

一般来说,这个解决方案基本上是解决在嵌套字典中查找键,所以这不是mongodb特定的。

这对我来说很有效:

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

我有一个更简单的工作…

你能做的是插入数据/文档到你的主集合“东西”,你必须在一个单独的集合中插入属性,让我们说“things_attributes”。

所以每次你插入"things"时,你确实会从"things_attributes"中得到该文档的值与你的新文档键的值进行比较,如果有任何新键存在,则将其追加到该文档中并再次重新插入它。

所以things_attributes只有一个唯一键的文档你可以通过findOne()很容易地得到

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