unwind inner framework mongodb mongodb-query aggregation-framework lookup

inner - Búsqueda anidada de MongoDB con 3 niveles



mongodb aggregate where clause (2)

Necesito recuperar toda la jerarquía de un solo objeto de la base de datos como JSON. En realidad, la propuesta sobre cualquier otra solución para lograr este resultado sería altamente valorada. Decidí usar MongoDB con su soporte de $ lookup.

Así que tengo tres colecciones:

partido

{ "_id" : "2", "name" : "party2" } { "_id" : "5", "name" : "party5" } { "_id" : "4", "name" : "party4" } { "_id" : "1", "name" : "party1" } { "_id" : "3", "name" : "party3" }

dirección

{ "_id" : "a3", "street" : "Address3", "party_id" : "2" } { "_id" : "a6", "street" : "Address6", "party_id" : "5" } { "_id" : "a1", "street" : "Address1", "party_id" : "1" } { "_id" : "a5", "street" : "Address5", "party_id" : "5" } { "_id" : "a2", "street" : "Address2", "party_id" : "1" } { "_id" : "a4", "street" : "Address4", "party_id" : "3" }

direcciónComentar

{ "_id" : "ac2", "address_id" : "a1", "comment" : "Comment2" } { "_id" : "ac1", "address_id" : "a1", "comment" : "Comment1" } { "_id" : "ac5", "address_id" : "a5", "comment" : "Comment6" } { "_id" : "ac4", "address_id" : "a3", "comment" : "Comment4" } { "_id" : "ac3", "address_id" : "a2", "comment" : "Comment3" }

Necesito recuperar todas las partes con todas las direcciones correspondientes y los comentarios de la dirección como parte del registro. Mi agregación:

db.party.aggregate([{ $lookup: { from: "address", localField: "_id", foreignField: "party_id", as: "address" } }, { $unwind: "$address" }, { $lookup: { from: "addressComment", localField: "address._id", foreignField: "address_id", as: "address.addressComment" } }])

El resultado es bastante raro. Algunos registros están bien. Pero falta Party con _id 4 (no hay una dirección para ello). También hay dos Party _id 1 en el conjunto de resultados (pero con direcciones diferentes):

{ "_id": "1", "name": "party1", "address": { "_id": "2", "street": "Address2", "party_id": "1", "addressComment": [{ "_id": "3", "address_id": "2", "comment": "Comment3" }] } }{ "_id": "1", "name": "party1", "address": { "_id": "1", "street": "Address1", "party_id": "1", "addressComment": [{ "_id": "1", "address_id": "1", "comment": "Comment1" }, { "_id": "2", "address_id": "1", "comment": "Comment2" }] } }{ "_id": "3", "name": "party3", "address": { "_id": "4", "street": "Address4", "party_id": "3", "addressComment": [] } }{ "_id": "5", "name": "party5", "address": { "_id": "5", "street": "Address5", "party_id": "5", "addressComment": [{ "_id": "5", "address_id": "5", "comment": "Comment5" }] } }{ "_id": "2", "name": "party2", "address": { "_id": "3", "street": "Address3", "party_id": "2", "addressComment": [{ "_id": "4", "address_id": "3", "comment": "Comment4" }] } }

Por favor, ayúdame con esto. Soy bastante nuevo en MongoDB pero siento que puede hacer lo que necesito.


Con la sintaxis de $lookup mongodb 3.6 y superior, es muy sencillo unir campos anidados sin usar $unwind .

db.party.aggregate([ { "$lookup": { "from": "address", "let": { "partyId": "$_id" }, "pipeline": [ { "$match": { "$expr": { "$eq": ["$party_id", "$$partyId"] }}}, { "$lookup": { "from": "addressComment", "let": { "addressId": "$_id" }, "pipeline": [ { "$match": { "$expr": { "$eq": ["$address_id", "$$addressId"] }}} ], "as": "address" }} ], "as": "address" }}, { "$unwind": "$address" } ])


La causa de sus ''problemas'' es la segunda etapa de agregación: { $unwind: "$address" } . Elimina el registro de la parte con _id: 4 (porque su matriz de direcciones está vacía, como usted menciona) y produce dos registros para las partes _id: 1 y _id: 5 (porque cada una de ellas tiene dos direcciones).

  • Para evitar que se eliminen partes sin direcciones, debe establecer la opción preserveNullAndEmptyArrays de la etapa $unwind en true .

  • Para evitar la duplicación de partes para sus diferentes direcciones, debe agregar la etapa de agregación de $group a su canalización. Además, use $project stage con $filter operator para excluir registros de direcciones vacías en la salida.

db.party.aggregate([{ $lookup: { from: "address", localField: "_id", foreignField: "party_id", as: "address" } }, { $unwind: { path: "$address", preserveNullAndEmptyArrays: true } }, { $lookup: { from: "addressComment", localField: "address._id", foreignField: "address_id", as: "address.addressComment", } }, { $group: { _id : "$_id", name: { $first: "$name" }, address: { $push: "$address" } } }, { $project: { _id: 1, name: 1, address: { $filter: { input: "$address", as: "a", cond: { $ifNull: ["$$a._id", false] } } } } }]);