Cómo encontrar el nombre de campo de MongoDB a profundidad arbitraria

Importé algún tipo de datos XML descuidados en una base de datos de Mongo. Cada documento ha nested sub documentos a una profundidad de alrededor de 5-10. Me gustaría encontrar () documentos que tienen un valor particular de un campo particular, donde el campo puede aparecer a cualquier profundidad en los subdocumentos (y puede aparecer varias veces).

Actualmente estoy tirando de cada documento en Python y luego buscando ese diccionario, pero sería bueno si pudiera indicar un prototipo de filtro donde la base de datos solo devolvería documentos que tienen un valor particular del nombre del campo en algún lugar de sus contenidos.

Aquí hay un documento de ejemplo:

{ "foo": 1, "bar": 2, "find-this": "Yes!", "stuff": { "baz": 3, "gobble": [ "wibble", "wobble", { "all-fall-down": 4, "find-this": "please find me" } ], "plugh": { "plove": { "find-this": "Here too!" } } } } 

Entonces, me gustaría encontrar documentos que tengan un campo “find-this” y (si es posible) para poder encontrar documentos que tengan un valor particular de un campo “find-this”.

Tiene razón en la statement cierta de que un documento BSON no es un documento XML. Como XML se carga en una estructura de árbol que comprende “nodos”, la búsqueda en una clave arbitraria es bastante fácil.

Un documento MonoDB no es tan simple de procesar, y esta es una “base de datos” en muchos aspectos, por lo que generalmente se espera que tenga cierta “uniformidad” de ubicaciones de datos para facilitar el “índice” y la búsqueda.

No obstante, se puede hacer. Pero, por supuesto, esto significa un proceso recursivo que se ejecuta en el servidor y esto significa procesamiento de JavaScript con $where .

Como ejemplo de shell básico, pero la function general es solo un argumento de cadena para el operador $where cualquier otro lugar:

 db.collection.find( function () { var findKey = "find-this", findVal = "please find me"; function inspectObj(doc) { return Object.keys(doc).some(function(key) { if ( typeof(doc[key]) == "object" ) { return inspectObj(doc[key]); } else { return ( key == findKey && doc[key] == findVal ); } }); } return inspectObj(this); } ) 

Básicamente, pruebe las claves presentes en el objeto para ver si coinciden con el “nombre de campo” y el contenido deseados. Si una de esas teclas pasa a ser un “objeto”, recurra a la función e inspeccione nuevamente.

JavaScript .some() se asegura de que la “primera” coincidencia encontrada regrese de la función de búsqueda dando un resultado true y devolviendo el objeto donde esa “clave / valor” estuvo presente a cierta profundidad.

Tenga en cuenta que $where esencialmente significa atravesar toda su colección a menos que haya algún otro filtro de consulta válido que pueda aplicarse a un “índice” en la colección.

Así que úselo con cuidado, o no lo haga en absoluto y simplemente trabaje con la reconstrucción de los datos en una forma más viable.

Pero esto te dará tu coincidencia.

Aquí hay un ejemplo, que utilizo para la búsqueda recursiva de Key-Value en cualquier parte de la estructura del documento:

 db.getCollection('myCollection').find({ "$where" : function(){ var searchKey = 'find-this'; var searchValue = 'please find me'; return searchInObj(obj); function searchInObj(obj){ for(var k in obj){ if(typeof obj[k] == 'object' && obj[k] !== null){ if(searchInObj(obj[k])){ return true; } } else { if(k == searchKey && obj[k] == searchValue){ return true; } } } return false; } } })