Necesito recuperar todo de una sola jerarquía de objetos de la base de datos como un JSON. En realidad la propuesta acerca de cualquier otra solución para conseguir este resultado sería muy appriciated. Decidí usar MongoDB con su $de búsqueda de apoyo.

Así que tengo tres colecciones:

parte

{ "_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" }

addressComment

{ "_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 sus correspondientes direcciones y dirección de comentarios 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"
    }
}])

Que el resultado es bastante raro. Algunos registros están bien. Pero Parte con _id 4 falta (no hay ninguna dirección). También hay dos Partes _id 1 en el conjunto de resultados, pero con diferentes direcciones):

{
"_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 me ayude con esto. Soy bastante nuevo para la MongoDB pero siento que puedo hacer lo que tengo de ella.

OriginalEl autor Yuriy | 2016-03-15

2 Comentarios

  1. 39

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

    • Para prevenir la remoción de partes sin direcciones debe establecer preserveNullAndEmptyArrays opción de $relajarse etapa true.

    • Para evitar la duplicación de partes para sus diferentes direcciones debe agregar $group agregación de etapa para su canalización. También, el uso de $proyecto etapa con $filter operador para excluir vacío registros de dirección de la producción.

    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] } }
    } 
    }
    }]);
    Tanque Shad! Hay un pequeño problema con registro de 4: { "_id": "4", "name": "party4", "address": [{ "addressComment": [] }] } Como se puede ver – dirección debe ser nulo, pero es un registro vacío en lugar de… Podemos omitir la dirección si su addressComment está vacía? En otro caso, esta dirección será considerado un récord.
    En realidad veo que siempre la solución funciona como se esperaba de acuerdo a la descripción de los nuevos «preserveNullAndEmptyArrays» campo para $relajarse operación (desde 3.2). Ahora podemos omitir el «$proyecto» paso a paso y especificar esta «$relajarse» en lugar de la simple: $unwind: {path: "$address",preserveNullAndEmptyArrays: true}.Voy a aceptar tu respuesta, gracias por la rápida y clara respuesta!
    Tengo una gran pregunta similar. Aquí OP código sólo tiene una propiedad llamada name en party colección y por lo tanto se utiliza $first para conseguir en la $group. Supongamos que tengo 10+ propiedades, entonces es hay alguna forma de obtener automáticamente todas las propiedades sin mencionar a cada uno de forma individual?
    ¿Cómo podemos agregar una cláusula group para «addressComment» si hubo comentarios diferentes para el mismo id de dirección? Como se mencionó esta consulta funciona bien para la agrupación en «dirección».

    OriginalEl autor Shad

  2. 5

    Con mongodb 3.6 y por encima de $de búsqueda sintaxis es bastante sencilla de unirse a campos anidados sin usar $relajarse.

    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" }
    ])
    "let": { "addressId", "$_id" }, debe ser "let": { "addressId": "$_id" },
    Absolutamente!!! Gracias @StathisNtonas.
    Eres bienvenido 🙂

    OriginalEl autor Anthony Winzlet

Dejar respuesta

Please enter your comment!
Please enter your name here