OK, det här är lite mer komplicerat eftersom du måste använda lite rekursion.
För att få rekursionen att hända måste du kunna lagra vissa funktioner på servern.
Steg 1:definiera vissa funktioner och placera dem på serversidan
isArray = function (v) {
return v && typeof v === 'object' && typeof v.length === 'number' && !(v.propertyIsEnumerable('length'));
}
m_sub = function(base, value){
for(var key in value) {
emit(base + "." + key, null);
if( isArray(value[key]) || typeof value[key] == 'object'){
m_sub(base + "." + key, value[key]);
}
}
}
db.system.js.save( { _id : "isArray", value : isArray } );
db.system.js.save( { _id : "m_sub", value : m_sub } );
Steg 2:definiera kartan och reducera funktioner
map = function(){
for(var key in this) {
emit(key, null);
if( isArray(this[key]) || typeof this[key] == 'object'){
m_sub(key, this[key]);
}
}
}
reduce = function(key, stuff){ return null; }
Steg 3:kör kartan förminskning och titta på resultat
mr = db.runCommand({"mapreduce" : "things", "map" : map, "reduce" : reduce,"out": "things" + "_keys"});
db[mr.result].distinct("_id");
Resultaten du får är:
["_id", "_id.isObjectId", "_id.str", "_id.tojson", "egg", "egg.0", "foo", "foo.bar", "foo.bar.baaaar", "hello", "type", "type.0", "type.1"]
Det finns ett uppenbart problem här, vi lägger till några oväntade fält här:1. _id-data2. .0 (på ägg och typ)
Steg 4:Några möjliga korrigeringar
För problem #1 åtgärden är relativt enkel. Ändra bara map
fungera. Ändra detta:
emit(base + "." + key, null); if( isArray...
till detta:
if(key != "_id") { emit(base + "." + key, null); if( isArray... }
Problem #2 är lite mer knäpp. Du ville ha alla nycklar och tekniskt "egg.0" är en giltig nyckel. Du kan ändra m_sub
att ignorera sådana numeriska tangenter. Men det är också lätt att se en situation där detta slår tillbaka. Säg att du har en associativ array inuti en vanlig array, då vill du att "0" ska visas. Jag överlåter resten av den lösningen till dig.