I'd untuk mendapatkan nama-nama semua tombol dalam MongoDB koleksi.
Misalnya, dari ini:
db.things.insert( { type : ['dog', 'cat'] } );
db.things.insert( { egg : ['cat'] } );
db.things.insert( { type : [] } );
db.things.insert( { hello : [] } );
I'a untuk mendapatkan kunci unik:
type, egg, hello
Anda bisa melakukan ini dengan 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"
})
Kemudian jalankan berbeda pada koleksi yang dihasilkan sehingga dapat menemukan semua kunci:
db[mr.result].distinct("_id")
["foo", "bar", "baz", "_id", ...]
Dengan Kristina's jawaban sebagai inspirasi, saya menciptakan sebuah alat open source yang disebut Variasi yang tidak tepat ini: https://github.com/variety/variety
Anda dapat menggunakan agregasi dengan yang baru $objectToArrray
di 3.4.4
versi untuk mengkonversi semua tombol atas & pasangan nilai ke dokumen array diikuti oleh $bersantai
& $kelompok
dengan $addToSet
untuk mendapatkan kunci yang berbeda di seluruh koleksi.
$$AKAR
untuk referensi tingkat atas dokumen.
db.things.aggregate([
{"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
{"$unwind":"$arrayofkeyvalue"},
{"$group":{"_id":null,"allkeys":{"$addToSet":"$arrayofkeyvalue.k"}}}
])
Anda dapat menggunakan query di bawah ini untuk mendapatkan kunci dalam satu dokumen.
db.things.aggregate([
{"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
{"$project":{"keys":"$arrayofkeyvalue.k"}}
])
Jika target anda koleksi ini tidak terlalu besar, anda dapat mencoba ini di bawah mongo shell client:
var allKeys = {};
db.YOURCOLLECTION.find().forEach(function(doc){Object.keys(doc).forEach(function(key){allKeys[key]=1})});
allKeys;
Berikut adalah contoh bekerja di Python: Sampel ini kembali hasil 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']
Dibersihkan dan dapat digunakan kembali solusi menggunakan 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')
Penggunaan:
get_keys('dbname', 'collection')
>> ['key1', 'key2', ... ]
Jika anda menggunakan mongodb 3.4.4 dan di atas maka anda dapat menggunakan berikut agregasi menggunakan $objectToArray
$kelompok
agregasi
db.collection.aggregate([
{ "$project": {
"data": { "$objectToArray": "$$ROOT" }
}},
{ "$project": { "data": "$data.k" }},
{ "$unwind": "$data" },
{ "$group": {
"_id": null,
"keys": { "$addToSet": "$data" }
}}
])
Berikut ini adalah kerja contoh
Saya terkejut, ada orang di sini memiliki ans dengan menggunakan simple javascript
dan Mengatur
logika untuk secara otomatis menyaring nilai-nilai duplikat, contoh sederhana di mongo shellseperti di bawah ini:
var allKeys = new Set()
db.collectionName.find().forEach( function (o) {for (key in o ) allKeys.add(key)})
for(let key of allKeys) print(key)
Ini akan mencetak semua tamu unik kunci dalam nama koleksi: collectionName.
Ini bekerja dengan baik bagi saya:
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);
}
Untuk mendapatkan daftar semua tombol minus _id
, mempertimbangkan menjalankan berikut agregat pipa:
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"];
Saya pikir cara terbaik melakukan ini seperti yang disebutkan di sini di mongod 3.4.4+ tetapi tanpa menggunakan $bersantai
operator dan hanya menggunakan dua tahap dalam pipa. Sebagai gantinya kita dapat menggunakan $mergeObjects
dan $objectToArray
operator.
Di $kelompok
panggung, kita gunakan $mergeObjects
operator untuk kembali dokumen tunggal di mana kunci/nilai dari semua dokumen dalam koleksi.
Kemudian datang $project
di mana kita menggunakan $peta
dan $objectToArray
untuk kembali kunci.
let allTopLevelKeys = [
{
"$group": {
"_id": null,
"array": {
"$mergeObjects": "$$ROOT"
}
}
},
{
"$project": {
"keys": {
"$map": {
"input": { "$objectToArray": "$array" },
"in": "$$this.k"
}
}
}
}
];
Sekarang jika kita telah bersarang dokumen dan ingin mendapatkan kunci juga, ini bisa dilakukan. Untuk kesederhanaan, mari mempertimbangkan dokumen dengan sederhana tertanam dokumen yang terlihat seperti ini:
{field1: {field2: "abc"}, field3: "def"}
{field1: {field3: "abc"}, field4: "def"}
Berikut pipa hasil semua tombol (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"
}
}
]
}
}
}
]
Dengan sedikit usaha, kita bisa mendapatkan kunci untuk semua subdocument dalam berbagai bidang di mana unsur-unsur objek juga.
Berikut benang dari @James Cropcho's jawaban, saya mendarat di berikut yang saya temukan untuk menjadi super mudah digunakan. Itu adalah biner alat, yang persis apa yang saya cari: mongoeye.
Menggunakan alat ini butuh waktu sekitar 2 menit untuk mendapatkan skema yang diekspor dari baris perintah.
Saya mencoba untuk menulis di nodejs dan akhirnya datang dengan ini:
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');
});
});
Setelah membaca baru dibuat collection "allFieldNames", hapus itu.
db.collection("allFieldNames").remove({}, function (err,result) {
db.close();
return;
});
Sesuai mongoldb dokumentasi, kombinasi dari berbeda
Menemukan nilai-nilai yang berbeda untuk bidang tertentu di koleksi tunggal atau melihat dan mengembalikan hasil dalam array.
dan indeks koleksi operasi apa yang akan mengembalikan semua nilai yang mungkin untuk kunci tertentu, atau indeks:
Mengembalikan array yang menyimpan daftar dari dokumen-dokumen yang mengidentifikasi dan mendeskripsikan indeks yang ada pada koleksi
Jadi di suatu metode yang bisa dilakukan menggunakan metode seperti yang berikut ini, dalam rangka untuk query koleksi untuk semua itu's terdaftar indeks, dan kembali, mengatakan sebuah objek dengan indeks untuk kunci (contoh ini menggunakan async/menanti untuk NodeJS, tapi jelas anda bisa menggunakan pendekatan asinkron):
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;
}
}
}
Jadi query koleksi dengan dasar _id
index, akan kembali berikut (test koleksi hanya memiliki satu dokumen pada saat tes):
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..
})
});
Pikiran anda, ini menggunakan metode asli untuk NodeJS Driver. Karena beberapa jawaban yang lain telah menyarankan, ada pendekatan-pendekatan lain, seperti agregat framework. Saya pribadi menemukan pendekatan ini lebih fleksibel, seperti anda dapat dengan mudah membuat dan menyempurnakan cara untuk mengembalikan hasil. Jelas, ini hanya membahas top-level atribut, tidak bersarang orang-orang.
Juga, untuk menjamin bahwa semua dokumen yang diwakili harus ada indeks sekunder (selain yang utama _id satu), indeks harus di set sebagai diperlukan
.
Mungkin sedikit off-topic, tapi anda dapat secara rekursif cantik-cetak semua tombol/bidang dari suatu benda:
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)
}
Berguna ketika semua objek dalam koleksi memiliki struktur yang sama.
Kita bisa mencapai hal ini dengan Menggunakan mongo js file. Tambahkan kode di bawah ini pada anda getCollectionName.js file dan jalankan file js di konsol Linux seperti yang diberikan di bawah ini :
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();
Terima kasih @ackuser
Saya diperpanjang Carlos LM's solusi sedikit sehingga's lebih rinci.
Contoh skema:
var schema = {
_id: 123,
id: 12,
t: 'title',
p: 4.5,
ls: [{
l: 'lemma',
p: {
pp: 8.9
}
},
{
l: 'lemma2',
p: {
pp: 8.3
}
}
]
};
Jenis ke 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;
}
}
}
Run:
schemafy(db.collection.findOne());
Output
_id <number>
id <number>
t <string>
p <number>
ls <object>:
0 <object>:
l <string>
p <object>:
pp <number>
Saya memiliki 1 sederhana mengatasi...
Apa yang dapat anda lakukan adalah saat memasukkan data/dokumen ke dalam koleksi utama "sesuatu" anda harus menyisipkan atribut dalam 1 pengumpulan terpisah memungkinkan mengatakan "things_attributes".
jadi setiap kali anda memasukkan dalam "sesuatu", anda mendapatkan dari "things_attributes" membandingkan nilai-nilai dari dokumen tersebut dengan dokumen baru anda kunci jika kunci baru hadir menambahkan dalam dokumen dan kembali re-insert itu.
Jadi things_attributes hanya akan memiliki 1 dokumen kunci unik yang anda dapat dengan mudah dapatkan ketika pernah anda butuhkan dengan menggunakan findOne()