Ayuda de MongoDB Query – consulta sobre los valores de cualquier clave en un subobjeto

Quiero realizar una consulta en esta colección para determinar qué documentos tienen claves en cosas que coinciden con un cierto valor. es posible?

Tengo una colección de documentos como:

{ "things": { "thing1": "red", "thing2": "blue", "thing3": "green" } } 

EDITAR: por concisión

Sugeriría un cambio de esquema para que pueda hacer consultas razonables en MongoDB.

De:

 { "userId": "12347", "settings": { "SettingA": "blue", "SettingB": "blue", "SettingC": "green" } } 

a:

 { "userId": "12347", "settings": [ { name: "SettingA", value: "blue" }, { name: "SettingB", value: "blue" }, { name: "SettingC", value: "green" } ] } 

Luego, puede indexar en "settings.value" , y hacer una consulta como:

 db.settings.ensureIndex({ "settings.value" : 1}) db.settings.find({ "settings.value" : "blue" }) 

El cambio es realmente simple …, ya que mueve el nombre de configuración y el valor de configuración a campos completamente indexables, y almacena la lista de configuraciones como una matriz.

Si no puede cambiar el esquema, puede probar la solución de @JohnnyHK , pero tenga en cuenta que básicamente es el peor de los casos en términos de rendimiento y que no funcionará eficazmente con los índices.

Si no sabe cuáles serán las claves y necesita que sean interactivas, necesitará usar el operador $where (notoriamente desafiado por el rendimiento) $where (como en el shell):

 db.test.find({$where: function() { for (var field in this.settings) { if (this.settings[field] == "red") return true; } return false; }}) 

Si tiene una gran colección, esto puede ser demasiado lento para sus propósitos, pero es su única opción si su conjunto de claves es desconocido.

Actualización de MongoDB 3.6

Ahora puede hacer esto sin $where usando el operador de agregación $objectToArray :

 db.test.aggregate([ // Project things as a key/value array, along with the original doc {$project: { array: {$objectToArray: '$things'}, doc: '$$ROOT' }}, // Match the docs with a field value of 'red' {$match: {'array.v': 'red'}}, // Re-project the original doc {$replaceRoot: {newRoot: '$doc'}} ]) 

Lamentablemente, ninguna de las respuestas anteriores aborda el hecho de que mongo puede contener valores nesteds en matrices u objetos nesteds.

ESTA ES LA PREGUNTA CORRECTA:

 {$where: function() { var deepIterate = function (obj, value) { for (var field in obj) { if (obj[field] == value){ return true; } var found = false; if ( typeof obj[field] === 'object') { found = deepIterate(obj[field], value) if (found) { return true; } } } return false; }; return deepIterate(this, "573c79aef4ef4b9a9523028f") }} 

Como la invocación de typeof en array u objeto nested devolverá ‘object’, esto significa que la consulta iterará en todos los elementos nesteds y repetirá a través de todos ellos hasta que se encuentre la clave con valor.

Puede verificar las respuestas anteriores con un valor nested y los resultados estarán lejos de ser deseados.

La encadenamiento de todo el objeto es un golpe en el rendimiento ya que tiene que iterar a través de todos los sectores de memoria uno por uno tratando de hacer coincidirlos. Y crea una copia del objeto como una cadena en memoria RAM (ambas ineficientes ya que la consulta usa más ram y slow ya que el contexto de la función ya tiene un objeto cargado).

La consulta en sí misma puede funcionar con objectId, string, int y cualquier tipo de javascript básico que desee.