mongodb mongodb-query aggregation-framework

mongodb - Múltiples condiciones de unión con el operador de búsqueda $



mongodb-query aggregation-framework (3)

Aquí está mi colección:

colección1:

{ user1: 1, user2: 2, percent: 0.56 }

colección2:

{ user1: 1, user2: 2, percent: 0.3 }

Quiero unir las dos colecciones por ''usuario1'' y ''usuario2''.

El resultado como este:

{ user1: 1, user2: 2, percent1: 0.56, percent2: 0.3 }

¿Cómo escribo la tubería?


Podemos hacer múltiples condiciones de unión con el operador de canalización de agregación $lookup en la versión 3.6 y posteriores.

Necesitamos asignar los valores de los campos a la variable usando el campo opcional let ; luego accede a esas variables en las etapas del campo de pipeline donde especifica la canalización que se ejecutará en las colecciones.

Tenga en cuenta que en la etapa $match , usamos el operador de consulta de evaluación $expr para comparar el valor de los campos.

La última etapa en la tubería es la etapa de tubería de agregación $replaceRoot donde simplemente $replaceRoot el resultado de $lookup con parte del documento $$ROOT utilizando el operador $mergeObjects .

db.collection2.aggregate([ { $lookup: { from: "collection1", let: { firstUser: "$user1", secondUser: "$user2" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: [ "$user1", "$$firstUser" ] }, { $eq: [ "$user2", "$$secondUser" ] } ] } } } ], as: "result" } }, { $replaceRoot: { newRoot: { $mergeObjects:[ { $arrayElemAt: [ "$result", 0 ] }, { percent1: "$$ROOT.percent1" } ] } } } ] )

Esta tubería produce algo parecido a esto:

{ "_id" : ObjectId("59e1ad7d36f42d8960c06022"), "user1" : 1, "user2" : 2, "percent" : 0.3, "percent1" : 0.56 }

Si no tiene la versión 3.6+, primero puede unirse usando uno de sus campos, digamos "usuario1" y luego desde allí desenrolla la matriz del documento coincidente usando el operador de canalización de agregación $unwind . La siguiente etapa en la tubería es la etapa $redact donde filtra aquellos documentos donde el valor de "usuario2" de la colección "unida" y el documento de entrada no son iguales usando las variables de sistema $$KEEP y $$PRUNE . Luego puede remodelar su documento en la etapa $project .

db.collection1.aggregate([ { "$lookup": { "from": "collection2", "localField": "user1", "foreignField": "user1", "as": "collection2_doc" }}, { "$unwind": "$collection2_doc" }, { "$redact": { "$cond": [ { "$eq": [ "$user2", "$collection2_doc.user2" ] }, "$$KEEP", "$$PRUNE" ] }}, { "$project": { "user1": 1, "user2": 1, "percent1": "$percent", "percent2": "$collection2_doc.percent" }} ])

que produce:

{ "_id" : ObjectId("572daa87cc52a841bb292beb"), "user1" : 1, "user2" : 2, "percent1" : 0.56, "percent2" : 0.3 }

Si los documentos en sus colecciones tienen la misma estructura y usted se encuentra realizando esta operación con frecuencia, entonces debería considerar fusionar las dos colecciones en una o insertar los documentos en esas colecciones en una nueva colección.

db.collection3.insertMany( db.collection1.find({}, {"_id": 0}) .toArray() .concat(db.collection2.find({}, {"_id": 0}).toArray()) )

Luego $group sus documentos por "usuario1" y "usuario2"

db.collection3.aggregate([ { "$group": { "_id": { "user1": "$user1", "user2": "$user2" }, "percent": { "$push": "$percent" } }} ])

cuyos rendimientos:

{ "_id" : { "user1" : 1, "user2" : 2 }, "percent" : [ 0.56, 0.3 ] }


Puede hacer múltiples coincidencias de campo usando $ match y $ project pipelines. (vea la respuesta detallada aquí - mongoDB Únase en múltiples campos )

db.collection1.aggregate([ {"$lookup": { "from": "collection2", "localField": "user1", "foreignField": "user1", "as": "c2" }}, {"$unwind": "$c2"}, {"$project": { "user2Eq": {"$eq": ["$user2", "$c2.user2"]}, "user1": 1, "user2": 1, "percent1": "$percent", "percent2": "$c2.percent" }}, {"$match": { {"user2Eq": {"$eq": True}} }}, {"$project": { "user2Eq": 0 }} ])


Si está intentando modelar sus datos y vino aquí para verificar si mongodb puede realizar uniones en múltiples campos antes de decidir hacerlo, siga leyendo.

Si bien MongoDB puede realizar uniones, también tiene la libertad de modelar datos de acuerdo con el patrón de acceso de su aplicación. Si los datos son tan simples como se presentan en la pregunta, simplemente podemos mantener una colección única que se vea así:

{ user1: 1, user2: 2, percent1: 0.56, percent2: 0.3 }

Ahora puede realizar todas las operaciones en esta colección que habría realizado uniéndose. ¿Por qué estamos tratando de evitar las uniones? Debido a que no son compatibles con colecciones fragmentadas ( docs ), lo que le impedirá escalar cuando sea necesario. La normalización de datos (que tiene tablas / colecciones separadas) funciona muy bien en SQL, pero cuando se trata de Mongo, evitar uniones puede ofrecer ventajas sin consecuencias en la mayoría de los casos. Use la normalización en MongoDB solo cuando no tenga otra opción. De los docs :

En general, use modelos de datos normalizados:

  • cuando la incrustación daría como resultado la duplicación de datos, pero no proporcionaría suficientes ventajas de rendimiento de lectura para superar las implicaciones de la duplicación.
  • para representar relaciones de muchos a muchos más complejas.
  • para modelar grandes conjuntos de datos jerárquicos.

Marque here para leer más sobre la inclusión y por qué la elegiría en lugar de la normalización.