Digamos que tengo estos documentos en mi colección:
{ foo: [ {bar: 1, baz: 2}, {bar: 3, baz: 4} ] } { foo: [ {bar: 5, baz: 6}, {bar: 7, baz: 8} ] } Cada documento contiene una matriz foo de subdocumentos. Ahora, esta consulta me permite encontrar todos los documentos donde foo es un superconjunto de [{bar: 1, baz: 2}, {bar: 3, baz: 4}] , es decir, donde están todos los (sub) documentos dados la matriz foo :
db.examples.find({ $and: [ { foo: { $elemMatch: { bar: 1, baz: 2 } } }, { foo: { $elemMatch: { bar: 3, baz: 4 } } } ] })Esto devuelve el primer documento como se esperaba.
Sin embargo, ¿cómo haría para encontrar los documentos donde foo es un subconjunto del término de búsqueda dado? Es decir, mi término de búsqueda es:
[{bar: 1, baz: 2}, {bar: 3, baz: 4}, {bar: 5, baz: 6}] Y quiero que coincida con el primer documento de la colección, pero no con el segundo (todos los subdocumentos en foo deben estar en el término de búsqueda dado).
Deberá hacer que su término de búsqueda sea una matriz bidimensional que se vea así.
let searchTerms = [ [1, 2], [3, 4], [5, 6] ];Esto se debe a que, como sabe, un objeto es un conjunto desordenado de pares de nombre/valor .
A partir de ahí, debe usar el operador $redact para realizar un procesamiento lógico $cond condición.
Su condición aquí es como $setIsSubset que devuelve verdadero cuando el elemento en la matriz de "entrada" es un subconjunto de su matriz de searchTerms de búsqueda.
Cuando $setIsSubset devuelve verdadero, $$KEEP el documento y descartarlo cuando devuelve falso usando la variable $$PRUNE .
Por supuesto, la primera expresión en $setIsSubset debe resolverse en una matriz bidimensional como su matriz "searchTerms". Y para hacer eso, necesita usar el operador de matriz $map que le permite aplicar una expresión a cada subdocumento en la matriz "foo". La expresión aquí usa el operador [] new en la versión 3.2 para devolver una matriz 2d donde el primer elemento en cada sub-matriz es el valor de "barra" y el último elemento el valor de "barra".
db.collection.aggregate([ { "$redact": { "$cond": [ { "$setIsSubset": [ { "$map": { "input": "$foo", "as": "f", "in": [ "$$f.bar", "$$f.baz" ]} }, searchTerms ]}, "$$KEEP", "$$PRUNE" ] }} ]) Finalmente, tenga en cuenta que $redact no usa índices.
$elemMatch con $nor selecciona todos los documentos con foo subdocuments que no coinciden con el término de búsqueda y $not para seleccionar los documentos donde foo subdocuments es un subconjunto del término de búsqueda.
Puede usar $nin en lugar de $nor también.
Es posible que desee incluir la condición $exist si tiene subdocumentos que no contienen los campos de búsqueda.
db.examples.find({ foo: { $not: { $elemMatch: { $nor: [{bar: 1,baz: 2},{bar: 3,baz: 4}, {bar: 5,baz: 6}] } } } });Puede usar setIsSubset en la canalización de agregación.
db.example.aggregate([ { $project : { foo : 1, criteria : { $literal : [{bar: 1, baz: 2}, {bar: 3, baz: 4}, {bar: 5, baz: 6}] } } }, { $project : { foo : 1, subset : { $setIsSubset : ["$foo", "$criteria"] } } }, { $match : { subset : true } }, { $project : { foo : 1 } } ])Producción:
{ "_id" : ..., "foo" : [ { "bar" : 1, "baz" : 2 }, { "bar" : 3, "baz" : 4 } ] } Nota: Puede usar una fase $match antes del primer $project que puede usar un índice.