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
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", ...]
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
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"}}
])
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);
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;
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()
)
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']
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);
}
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', ... ]
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.
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;
});
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"];
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
.
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
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>
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 ()
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) ; }
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