Récupère les noms de toutes les clés de la collection

Je voudrais obtenir les noms de toutes les clés dans une collection MongoDB.

Par exemple, à partir de ceci:

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

J’aimerais avoir les clés uniques:

 type, egg, hello 

Vous pouvez le faire avec 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" }) 

Ensuite, lancez la distinction sur la collection résultante pour trouver toutes les clés:

 db[mr.result].distinct("_id") ["foo", "bar", "baz", "_id", ...] 

Avec la réponse de Kristina comme source d’inspiration, j’ai créé un outil open source appelé Variety qui fait exactement cela: https://github.com/variety/variety

Vous pouvez utiliser l’agrégation avec le nouveau $objectToArrray dans la version 3.4.4 pour convertir toutes les paires clé / valeur supérieure en tableaux de documents, suivies de $unwind & $group avec $addToSet pour obtenir des clés distinctes pour l’ensemble de la collection.

$$ROOT pour référencer le document de niveau supérieur.

 db.things.aggregate([ {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}}, {"$unwind":"$arrayofkeyvalue"}, {"$group":{"_id":null,"allkeys":{"$addToSet":"$arrayofkeyvalue.k"}}} ]) 

Vous pouvez utiliser la requête ci-dessous pour obtenir des clés dans un seul document.

 db.things.aggregate([ {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}}, {"$project":{"keys":"$arrayofkeyvalue.k"}} ]) 

Essaye ça:

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

Si votre collection cible n’est pas trop grande, vous pouvez essayer ceci sous client mongo:

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

Utiliser python Renvoie l’ensemble de toutes les clés de niveau supérieur de la collection:

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

Voici l’exemple utilisé dans Python: Cet exemple renvoie les résultats en ligne.

 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'] 

Cela fonctionne très bien pour moi:

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

Une solution nettoyée et réutilisable utilisant 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') 

Usage:

 get_keys('dbname', 'collection') >> ['key1', 'key2', ... ] 

Je pense que la meilleure façon de le faire comme mentionné ici est dans mongod 3.4.4+ mais sans utiliser l’opérateur $unwind et en utilisant seulement deux étapes dans le pipeline. Au lieu de cela, nous pouvons utiliser les $mergeObjects et $objectToArray .

Dans la $group , nous utilisons l’opérateur $mergeObjects pour renvoyer un document unique dans lequel clé / valeur provient de tous les documents de la collection.

Vient ensuite le $project où nous utilisons $map et $objectToArray pour renvoyer les clés.

 let allTopLevelKeys = [ { "$group": { "_id": null, "array": { "$mergeObjects": "$$ROOT" } } }, { "$project": { "keys": { "$map": { "input": { "$objectToArray": "$array" }, "in": "$$this.k" } } } } ]; 

Maintenant, si nous avons des documents nesteds et que nous voulons également obtenir les clés, cela est faisable. Pour plus de simplicité, considérons un document avec un document incorporé simple qui ressemble à ceci:

 {field1: {field2: "abc"}, field3: "def"} {field1: {field3: "abc"}, field4: "def"} 

Le pipeline suivant génère toutes les clés (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" } } ] } } } ] 

Avec un petit effort, nous pouvons obtenir la clé pour tous les sous-documents dans un champ tableau où les éléments sont également object.

J’essayais d’écrire dans nodejs et j’ai finalement trouvé ceci:

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

Après avoir lu la nouvelle collection “allFieldNames”, supprimez-la.

 db.collection("allFieldNames").remove({}, function (err,result) { db.close(); return; }); 

Pour obtenir une liste de toutes les clés moins _id , envisagez d’exécuter le pipeline agrégé suivant:

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

Selon la documentation mongoldb, une combinaison de

Trouve les valeurs distinctes d’un champ spécifié dans une seule collection ou vue et renvoie les résultats dans un tableau.

et les opérations de collecte d’ index sont ce qui retournerait toutes les valeurs possibles pour une clé donnée, ou un index:

Retourne un tableau contenant une liste de documents identifiant et décrivant les index existants de la collection

Donc, dans une méthode donnée, on pourrait utiliser une méthode comme celle-ci, afin d’interroger une collection pour tous ses index enregistrés, et retourner, disons un object avec les index pour les clés (cet exemple utilise async / waiting pour NodeJS, mais de toute évidence, vous pouvez utiliser toute autre approche asynchrone):

 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 === "ssortingng") 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; } } } 

Ainsi, l’interrogation d’une collection avec l’index _id base renverrait le _id suivant (la collection de tests ne contient qu’un seul document au moment du test):

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

Attention, cela utilise des méthodes natives du pilote NodeJS. Comme d’autres réponses l’ont suggéré, il existe d’autres approches, telles que le cadre global. Personnellement, je trouve cette approche plus flexible, car vous pouvez facilement créer et affiner la manière de retourner les résultats. Evidemment, cela ne concerne que les atsortingbuts de haut niveau, pas ceux nesteds. De même, pour garantir que tous les documents sont représentés en présence d’index secondaires (autres que le principal _id), ces index doivent être définis comme required .

J’ai étendu la solution de Carlos LM pour que ce soit plus détaillé.

Exemple de schéma:

 var schema = { _id: 123, id: 12, t: 'title', p: 4.5, ls: [{ l: 'lemma', p: { pp: 8.9 } }, { l: 'lemma2', p: { pp: 8.3 } } ] }; 

Tapez dans la console:

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

Courir:

 schemafy(db.collection.findOne()); 

Sortie

 _id  id  t  p  ls : 0 : l  p : pp  

J’ai 1 travail plus simple autour de …

Ce que vous pouvez faire, c’est que lorsque vous insérez des données / documents dans votre collection principale, vous devez insérer les atsortingbuts dans une collection séparée, disons “things_atsortingbutes”.

ainsi, chaque fois que vous insérez des “choses”, vous obtenez de “things_atsortingbutes” comparez les valeurs de ce document avec vos nouvelles clés de document si une nouvelle clé présente l’ajoute dans ce document et le réinsère à nouveau.

Donc things_atsortingbutes aura seulement 1 document de clés uniques que vous pouvez facilement obtenir en utilisant findOne ()

 var schematodo = db.[collection].findOne(); for (var key in schematodo) { print (key) ; }