Получить имена всех ключей в коллекции

233

Я хотел бы получить имена всех ключей в коллекции MongoDB.

Например, из этого:

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

Я хочу получить уникальные ключи:

type, egg, hello
Теги:

12 ответов

258
Лучший ответ

Вы можете сделать это с помощью 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"
})

Затем запустите выделение в полученной коллекции, чтобы найти все ключи:

db[mr.result].distinct("_id")
["foo", "bar", "baz", "_id", ...]
  • 2
    Всем привет! Я только что опубликовал продолжение этого вопроса с вопросом, как заставить этот фрагмент работать даже с ключами, расположенными на более глубоких уровнях в структуре данных ( stackoverflow.com/questions/2997004/… ).
  • 1
    @kristina: Как это возможно, что я получаю все вещи, перечисленные с ключами при использовании этого в коллекции вещей . Это похоже на механизм истории, потому что я получаю вещи, которые я изменил в прошлом ..
Показать ещё 8 комментариев
169

С Kristina answer в качестве вдохновения я создал инструмент с открытым исходным кодом под названием Variety, который делает именно это: https://github.com/variety/variety

  • 13
    Это фантастический инструмент, поздравляю. Он делает именно то, что задает вопрос, и может быть настроен с ограничениями, глубиной и т. Д. Рекомендуется любым, кто следует.
  • 1
    Больше не работает :(
Показать ещё 1 комментарий
23

Попробуйте следующее:

doc=db.thinks.findOne();
for (key in doc) print(key);
  • 40
    неверный ответ, так как при этом выводятся только поля для одного документа в коллекции - все остальные могут иметь совершенно разные ключи.
  • 14
    Это все еще самый полезный ответ для меня, будучи простым разумным минимумом.
Показать ещё 6 комментариев
9

Использование 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()
)
  • 1
    Я нашел, что это работает, но насколько это эффективно по сравнению с необработанным запросом Mongod?
  • 1
    Я совершенно уверен, что это крайне неэффективно по сравнению с выполнением этого непосредственно в Mongodb
7

Если ваша целевая коллекция не слишком велика, вы можете попробовать это под клиентом оболочки mongo:

var allKeys = {};

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

allKeys;
  • 0
    вот как я могу дать regExp для определенных ключей, если я хочу видеть?
  • 0
    @ TB.M вы можете попробовать это: db.configs.find (). ForEach (function (doc) {Object.keys (doc) .forEach (function (key) {if (/YOURREGEXP/.test(key)) { AllKeys [ключ] = 1}})});
Показать ещё 2 комментария
6

Вы можете использовать агрегацию с новым $objectToArrray в 3.4.4 для преобразования всех верхних ключей и пары значений в массивы документов, за которыми следуют $unwind и $group с помощью $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"}})
  • 11
    Это действительно лучший ответ. Решает проблему, не задействуя какой-либо другой язык программирования или пакет, и работает со всеми драйверами, которые поддерживают агрегированную среду (даже Meteor!)
6

Вот образец, который работал в Python: Этот образец возвращает результаты inline.

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

Это отлично работает для меня:

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

Я пытался писать в 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; 
});
-1

Я немного расширил решение 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;
        }
    }
}

Run:

schemafy(db.collection.findOne());

Выход

_id <number>
id <number>
t <string>
p <number>
ls <object>:
    0 <object>:
    l <string>
    p <object>:
        pp <number> 
  • 3
    его ответ неверен, и вы основаны на нем. весь смысл в том, чтобы вывести все поля всех документов, а не первый документ, который может иметь поля, отличные от каждого следующего.
-3

У меня есть более простая работа вокруг...

Что вы можете сделать, это вставлять данные/документы в свою основную коллекцию "вещи", которые вы должны вставлять в одну отдельную коллекцию, позволяет сказать "things_attributes".

поэтому каждый раз, когда вы вставляете "вещи", вы получаете от "things_attributes" сравнение значений этого документа с вашими новыми ключами документа, если какой-либо новый ключ присутствует в этом документе и снова вставляет его.

Итак, у вещей-атрибутов будет только один документ уникальных ключей, который вы можете легко получить, когда захотите, используя findOne()

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню