web-dev-qa-db-ja.com

コレクション内のすべてのキーの名前を取得します

MongoDBコレクション内のすべてのキーの名前を取得したいのですが。

たとえば、これから:

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

一意のキーを取得したいのですが。

type, Egg, hello
289
Steve

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", ...]
315
kristina

クリスティーナの答え をインスピレーションとして、私はVarietyというオープンソースのツールを作成しました。これはまさにこれです。 https:// github.com/variety/variety

191
James Cropcho

$objectToArrray のnew 3.4.4 バージョンで集約を使用して、すべてのトップキーと値のペアをドキュメント配列に変換し、その後に $unwindコレクション全体で異なるキーを取得するには、$group with $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"}}
])
44
Veeram

これを試して:

doc=db.thinks.findOne();
for (key in doc) print(key);
19
Carlos LM

ターゲットコレクションがそれほど大きくない場合は、mongo Shellクライアントで試してみてください。

var allKeys = {};

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

allKeys;
14
Li Chunlin

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()
)
10
Laizer

これが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']
7
BobHy

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', ... ]
4
ifischer

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

これが実用的な です

3
Fanpark

これは私にとってはうまくいきます:

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

$unwind演算子を使用せず、パイプラインで2つのステージのみを使用することなく、ここで説明した こちら の最善の方法はmongod 3.4.4+にあります。代わりに、 $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"
                        }
                    }
                ]
            }
        }
    }
]

少しの努力で、要素がオブジェクトである配列フィールド内のすべてのサブ文書のキーを取得できます。

1
styvane

驚いたことに、重複した値を自動的にフィルタリングするために単純なjavascriptおよびSetロジックを使用しても答えがありません。mongo Shellの単純な例を次に示します。

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

これにより、コレクション名に含まれるすべての一意のキーが印刷されます。collectionName

1
krishna Prasad

すべてのキーから_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"];
1
chridam

多少話題から外れるかもしれませんが、オブジェクトのすべてのキー/フィールドを再帰的にきれいに印刷することができます。

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
qed

Mongoldb ドキュメント に従って、distinctの組み合わせ

単一のコレクションまたはビューにまたがって指定されたフィールドの固有値を見つけ、その結果を配列として返します。

そして インデックス コレクション操作は、与えられたキーまたはインデックスに対して可能なすべての値を返します。

コレクションの既存のインデックスを識別して記述するドキュメントのリストを保持する配列を返します

したがって、与えられたメソッドでは、登録されているすべてのインデックスについてコレクションをクエリして返すために、次のようなメソッドを使うことができます。明らかに他の任意の非同期アプローチを使用することができます。

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インデックスでコレクションをクエリすると、次のようになります(テストコレクションには、テスト時に1つのドキュメントしかありません)。

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として設定されるべきです。

0
jlmurph

私は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
Gautam

これを実現するには、mongo jsファイルを使用します。下記のコードをgetCollectionName.jsファイルに追加し、次に示すようにLinuxのコンソールでjsファイルを実行します。

mongo --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

0
Irshad Khan

@James Cropchoの答えからのスレッドに続いて、私は非常に使いやすいことがわかった次のものに到達しました。これはバイナリツールであり、まさに私が探していたものです。 mongoeye

このツールを使用すると、コマンドラインからスキーマをエクスポートするのに約2分かかりました。

0
paneer_tikka