Pobierz nazwy wszystkich kluczy w kolekcji

Chciałbym zdobyć nazwy wszystkich kluczy w kolekcji MongoDB.

Na przykład z tego:

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

Chciałbym dostać unikalne klucze:

type, egg, hello
Author: styvane, 2010-02-19

17 answers

Możesz to zrobić za pomocą 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"
})

Następnie uruchom distinct na wynikowej kolekcji, aby znaleźć wszystkie klucze:

db[mr.result].distinct("_id")
["foo", "bar", "baz", "_id", ...]
 294
Author: kristina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-09 14:27:00

Z odpowiedzią Kristiny jako inspiracją stworzyłem narzędzie open source o nazwie Variety, które robi dokładnie to: https://github.com/variety/variety

 182
Author: James Cropcho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:37

Możesz użyć agregacji z nowym $objectToArrray w 3.4.4 Wersja, aby przekonwertować wszystkie górne pary klawiszy i wartości na tablice dokumentów, a następnie$unwind & $group z $addToSet aby uzyskać różne klucze w całej kolekcji.

$$ROOT do odwoływania się do dokumentu najwyższego poziomu.

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

Możesz użyć poniższego zapytania, aby uzyskać klucze w jednym dokumencie.

db.things.aggregate([
  {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
  {"$project":{"keys":"$arrayofkeyvalue.k"}}
])
 28
Author: Veeram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-26 02:24:08

Spróbuj tego:

doc=db.thinks.findOne();
for (key in doc) print(key);
 19
Author: Carlos LM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-06 12:56:19

Jeśli Twoja kolekcja docelowa nie jest zbyt duża, możesz spróbować tego pod klientem powłoki mongo:

var allKeys = {};

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

allKeys;
 11
Author: Li Chunlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-26 06:38:57

Używanie Pythona. Zwraca zestaw wszystkich kluczy najwyższego poziomu w kolekcji:

#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
Author: Laizer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-11 09:12:18

Oto przykład pracy w Pythonie: Ta próbka zwraca wyniki w linii.

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
Author: BobHy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-25 00:42:24

To działa dobrze dla mnie:

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);
}
 1
Author: ackuser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-02 21:27:39

Oczyszczone i wielokrotnego użytku rozwiązanie przy użyciu 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')

Użycie:

get_keys('dbname', 'collection')
>> ['key1', 'key2', ... ]
 1
Author: ifischer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-05 16:53:14

Myślę, że najlepszym sposobem, jak wspomniano tutaj jest mongod 3.4.4+, ale bez użycia operatora $unwind i używając tylko dwóch etapów w potoku. Zamiast tego możemy użyć $mergeObjects oraz $objectToArray operatorzy.

W etapie $group używamy operatora $mergeObjects, aby zwrócić pojedynczy dokument, w którym klucz / wartość pochodzą ze wszystkich dokumentów w kolekcji.

Następnie przychodzi $project gdzie używamy $map i $objectToArray aby zwrócić klucze.

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

Teraz, jeśli mamy zagnieżdżone dokumenty i chcemy również uzyskać klucze, jest to wykonalne. Dla uproszczenia rozważmy dokument z prostym osadzonym dokumentem, który wygląda tak:

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

Następujący rurociąg wyświetla wszystkie klucze (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"
                        }
                    }
                ]
            }
        }
    }
]

Przy niewielkim wysiłku, możemy uzyskać klucz dla wszystkich subdokumentów w polu tablicy, gdzie elementy są również obiektami.

 1
Author: styvane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-10 21:12:57

Próbowałem napisać w nodejs i w końcu wpadłem na to:

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

Po przeczytaniu nowo utworzonej kolekcji "allFieldNames", usuń ją.

db.collection("allFieldNames").remove({}, function (err,result) {
     db.close();
     return; 
});
 0
Author: Gautam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-10 09:43:39

Aby uzyskać listę wszystkich kluczy minus _id, rozważ uruchomienie następującego zbiorczego potoku:

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"];
 0
Author: chridam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-25 21:59:25

Zgodnie z dokumentacją mongoldb , kombinacją distinct

Znajduje różne wartości dla określonego pola w pojedynczej kolekcji lub widoku i zwraca wyniki w tablicy.

I indeksy operacje kolekcji zwracają wszystkie możliwe wartości dla danego klucza, czyli indeks:

Zwraca tablicę zawierającą listę dokumentów identyfikujących i opisujących istniejące indeksy na kolekcja

Więc w danej metodzie można użyć metody takiej jak ta, aby odpytywać kolekcję o wszystkie zarejestrowane indeksy i zwracać, powiedzmy obiekt z indeksami dla kluczy (ten przykład używa asynchronicznego/oczekującego na NodeJS, ale oczywiście można użyć dowolnego innego podejścia asynchronicznego):

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

Więc zapytanie kolekcji z podstawowym indeksem _id zwróci następujące (zbiór testowy ma tylko jeden dokument w momencie 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..
        })
});

Pamiętaj, że używa się metod natywnych dla Sterownika NodeJS. Jak sugerowały inne odpowiedzi, istnieją inne podejścia, takie jak ramy zbiorcze. Osobiście uważam to podejście za bardziej elastyczne, ponieważ można łatwo tworzyć i dostrajać, Jak zwrócić wyniki. Oczywiście dotyczy to tylko atrybutów najwyższego poziomu, a nie zagnieżdżonych. Ponadto, aby zagwarantować, że wszystkie dokumenty są reprezentowane w przypadku istnienia indeksów drugorzędnych( innych niż główny _id), indeksy te należy ustawić jako required.

 0
Author: murphguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-14 23:44:00

Jeśli używasz mongodb 3.4.4 i nowszych, możesz użyć poniższej agregacji za pomocą $objectToArray Oraz $group operatory agregacji

db.collection.aggregate([
  { "$project": {
    "data": { "$objectToArray": "$$ROOT" }
  }},
  { "$project": { "data": "$data.k" }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": null,
    "keys": { "$addToSet": "$data" }
  }}
])

Oto praca przykład

 0
Author: Anthony Winzlet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-02 20:53:34

Rozszerzyłem nieco rozwiązanie Carlosa LM, żeby było bardziej szczegółowe.

Przykład schematu:

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

Wpisz do konsoli:

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

Wyjście

_id <number>
id <number>
t <string>
p <number>
ls <object>:
    0 <object>:
    l <string>
    p <object>:
        pp <number> 
 -1
Author: va5ja,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-28 13:37:47

Mam 12 lat...

Co możesz zrobić, to wstawiając dane / dokument do głównej kolekcji "rzeczy" musisz wstawić atrybuty w 1 oddzielnej kolekcji powiedzmy "things_attributes".

Więc za każdym razem, gdy wstawiasz do "rzeczy", otrzymujesz z "things_attributes" porównywanie wartości tego dokumentu z nowymi kluczami dokumentu, jeśli jakikolwiek nowy klucz dołącza go do tego dokumentu i ponownie go wstawia.

Więc things_attributes będzie miał tylko 1 Dokument unikalnych kluczy, które można łatwo uzyskać, gdy kiedykolwiek potrzebujesz, używając findOne ()

 -4
Author: Paresh Behede,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-21 11:41:39
var schematodo = db.[collection].findOne();
for (var key in schematodo) { print (key) ; }
 -7
Author: jinglining,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-26 07:38:07