Bien, esto es un poco más complejo porque necesitarás usar algo de recursividad.
Para que ocurra la recurrencia, deberá poder almacenar algunas funciones en el servidor.
Paso 1:definir algunas funciones y ponerlas del lado del servidor
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 } );
Paso 2:definir el mapa y reducir funciones
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; }
Paso 3:ejecuta el mapa reduce y mira los resultados
mr = db.runCommand({"mapreduce" : "things", "map" : map, "reduce" : reduce,"out": "things" + "_keys"});
db[mr.result].distinct("_id");
Los resultados que obtendrás son:
["_id", "_id.isObjectId", "_id.str", "_id.tojson", "egg", "egg.0", "foo", "foo.bar", "foo.bar.baaaar", "hello", "type", "type.0", "type.1"]
Aquí hay un problema obvio, estamos agregando algunos campos inesperados aquí:1. el _id datos2. el .0 (en huevo y tipo)
Paso 4:Algunas soluciones posibles
Para problema #1 la solución es relativamente fácil. Simplemente modifique el map
función. Cambia esto:
emit(base + "." + key, null); if( isArray...
a esto:
if(key != "_id") { emit(base + "." + key, null); if( isArray... }
Problema #2 es un poco más arriesgado. Querías todo teclas y técnicamente "egg.0" es una clave válida. Puede modificar m_sub
para ignorar dichas teclas numéricas. Pero también es fácil ver una situación en la que esto resulte contraproducente. Digamos que tiene una matriz asociativa dentro de una matriz normal, entonces quiere que aparezca ese "0". Dejaré el resto de esa solución en tus manos.