MongoDBコレクション内のすべてのキーの名前を取得したいと思います。
たとえば、これから:
db.things.insert( { type : ['dog', 'cat'] } );
db.things.insert( { egg : ['cat'] } );
db.things.insert( { type : [] } );
db.things.insert( { hello : [] } );
一意のキーを取得したい:
type, egg, hello
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 というオープンソース ツールを作成しました: https://github.com/variety/variety
$objectToArray
バージョン3.4.4の新しい集計演算子で集計を使用して、上位のすべてのキーと値のペアをドキュメント配列に変換し、その後に$unwind
and$group
を$addToSet
使用して、コレクション全体で個別のキーを取得できます。($$ROOT
最上位のドキュメントを参照するために使用します。)
db.things.aggregate([
{"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
{"$unwind":"$arrayofkeyvalue"},
{"$group":{"_id":null,"allkeys":{"$addToSet":"$arrayofkeyvalue.k"}}}
])
次のクエリを使用して、1 つのドキュメント内のキーを取得できます。
db.things.aggregate([
{"$match":{_id: "<<ID>>"}}, /* Replace with the document's ID */
{"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
{"$project":{"keys":"$arrayofkeyvalue.k"}}
])
ターゲット コレクションが大きすぎない場合は、mongo シェル クライアントでこれを試すことができます。
var allKeys = {};
db.YOURCOLLECTION.find().forEach(function(doc){Object.keys(doc).forEach(function(key){allKeys[key]=1})});
allKeys;
パイソンの使用。コレクション内のすべての最上位キーのセットを返します。
#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()
)
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']
これは私にとってはうまくいきます:
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);
}
私はパーティーに遅れていることを知っていますが、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 固有ではありません。
この質問が 10 年前のものであることは知っていますが、C# のソリューションはなく、これを理解するのに何時間もかかりました。私は.NETドライバーを使用しておりSystem.Linq
、キーのリストを返しています。
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());
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>
もっと簡単な回避策が1つあります...
できることは、データ/ドキュメントをメイン コレクションの「もの」に挿入するときに、属性を 1 つの別のコレクションに挿入する必要があることです。たとえば、「things_attributes」とします。
そのため、「things」に挿入するたびに、「things_attributes」から取得して、そのドキュメントの値を新しいドキュメント キーと比較します。新しいキーが存在する場合は、そのドキュメントに追加し、再度挿入します。
そのため、things_attributes には一意のキーのドキュメントが 1 つだけあり、findOne() を使用して必要なときにいつでも簡単に取得できます。