Tengo una colección determinada de MongoDb con documentos que se parecen a esto:
{ items: [ { id: 1, data: 'a' }, { id: 2, data: 'b' }, { id: 3, data: 'c' }, ] } Ahora tengo que $lookup en esta colección. Necesito los datos de la matriz del elemento con id = 2 donde id = 1 data coincide con el valor de búsqueda $$value . Mi primer intento ingenuo de encontrar el documento correcto se veía así:
$match { items: { $elemMatch: { id: 1, data: '$$value' } } } Pero el $$value no se evalúa, por lo que los datos se comparan con el literal en lugar de su valor. También traté de evaluar el valor usando $expr , pero no pude obtener la sintaxis correcta (¿si es posible?).
La única forma de trabajo en la que pude trabajar fue extrayendo los datos primero y luego haciendo la comparación:
[ { $project: { _id: 0, data1: { $filter: { input: '$items', as: 'item', cond: {$eq: ['$$item.id', 1]} } }, data2: { $filter: { input: '$items', as: 'item', cond: {$eq: ['$$item.id', 2]} } }, } }, { $set: { data1: {$arrayElemAt: ['$data1.data', 0]}, data2: {$arrayElemAt: ['$data2.data', 0]} } }, { $match: { $expr: {$eq: ['$data1', '$$value']} } } ]; Pero como era de esperar, este enfoque es mucho más lento. Para los datos involucrados, la consulta tomó más de 7 segundos, mientras que el enfoque superior (usando una constante en lugar de una variable $$value ) fue tres veces más rápido.
¿Es posible usar la variable $$value directamente en el operador $elemMatch ? ¿O hay alguna otra optimización disponible para acelerar la búsqueda de colecciones?
Entonces, primero entendamos por qué falló su enfoque ingenuo, los documentos de búsqueda canalizados de Mongo especifican que:
Una etapa $match requiere el uso de un operador $expr para acceder a las variables. $expr permite el uso de expresiones de agregación dentro de la sintaxis de $match.
Por lo tanto, solo se puede acceder al value de la variable que está definiendo al comienzo de la $lookup con el uso de $expr , ahora también especificado en los documentos de $expr :
Los argumentos pueden ser cualquier expresión de agregación válida
Lamentablemente para nosotros, $elemMatch no es una "expresión de agregación", ya que pertenece al "lenguaje de consulta". es por eso que tu primer enfoque falló. Simplemente no puede usar $elemMatch dentro de una $expr que se requiere para acceder al campo $$value .
Entonces, ¿qué podemos hacer? Bueno, puedes usar $filter como ya empezaste a hacer:
db.collection.aggregate([ { $lookup: { from: "collection2", let: { value: "$data" }, pipeline: [ { $match: { $expr: { $gt: [ { $size: { $filter: { input: "$items", as: "item", cond: { $and: [ { $eq: [ "$$item.id", 1 ] }, { $eq: [ "$$item.data", "$$value" ] } ] } } } }, 0 ], } } } ], as: "res" } } ])Sería más fácil responder completamente si proporciona la estructura completa de ambas colecciones y el resultado final requerido, ya que tuve que adivinar algunas de las cosas aquí para escribir esta canalización.