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
entrue
.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] } }
}
}
}]);