La fusión de la matriz de campos en MongoDB agregación

Es posible la combinación de la matriz de campos, mientras que el uso de MongoDB marco de agregación? Aquí está un resumen problema estoy tratando de resolver:

Muestra de documentos de entrada para la agregación:

{
  "Category" : 1,
  "Messages" : ["Msg1", "Msg2"],
  "Value" : 1
},
{
  "Category" : 1,
  "Messages" : [],
  "Value" : 10
},
{
  "Category" : 1,
  "Messages" : ["Msg1", "Msg3"],
  "Value" : 100
},
{
  "Category" : 2,
  "Messages" : ["Msg4"],
  "Value" : 1000
},
{
  "Category" : 2,
  "Messages" : ["Msg5"],
  "Value" : 10000
},
{
  "Category" : 3,
  "Messages" : [],
  "Value" : 100000
}

Queremos agrupar por Categoría de’ compartiendo ‘Valor’ y la fusión de ‘Mensajes’. He probado esta agregación de canalización:

{group : {
        _id : "$Category",
        Value : { $sum : "$Value"},
        Messages : {$push : "$Messages"}
    }
}, 
{$unwind : "$Messages"}, 
{$unwind : "$Messages"}, 
{$group : {
        _id : "$_id",
        Value : {$first : "$Value"},
        Messages : {$addToSet : "$Messages"}
    }
}

El resultado es:

"result" : [{
        "_id" : 1,
        "Value" : 111,
        "Messages" : ["Msg3", "Msg2", "Msg1"]
    }, 
    {
        "_id" : 2,
        "Value" : 11000,
        "Messages" : ["Msg5", "Msg4"]
    }
]

Sin embargo, esta completamente extraña a la Categoría 3, ya que los documentos en los que ‘Categoría’ está a 3 no tienen ningún ‘Mensajes’ y que son descartados por la segunda relajarse. Nos gustaría que el resultado de incluir los siguientes:

{
    "_id" : 3,
    "Value" : 100000,
    "Messages" : []
}

¿Hay una buena manera de lograr esto mediante la agregación de marco?

es Mensajes garantizado para estar allí como una matriz? O es posible que no existen o que estará ahí, pero como un tipo diferente?
sí Mensajes está garantizado para existir como un conjunto (que puede estar vacía para algunos registros).
has probado el preserveNullAndEmptyArrays opción para $unwind?
Esta pregunta se ha planteado cuando estábamos usando la v2.6. Creo que con preserveNullAndEmptyArrays debe hacer lo que estábamos buscando.

OriginalEl autor etkarayel | 2013-10-09

2 respuestas

  1. 12

    Aquí es un truco que puede utilizar si los Mensajes se garantiza que sea una matriz:

    > db.messages.find()
    { "Category" : 1, "Messages" : [  "Msg1",  "Msg2" ], "Value" : 1 }
    { "Category" : 1, "Messages" : [ ], "Value" : 10 }
    { "Category" : 1, "Messages" : [  "Msg1",  "Msg3" ], "Value" : 100 }
    { "Category" : 2, "Messages" : [  "Msg4" ], "Value" : 1000 }
    { "Category" : 2, "Messages" : [  "Msg5" ], "Value" : 10000 }
    { "Category" : 3, "Messages" : [ ], "Value" : 100000 }
    > var group1 = {
    "$group":   {
    "_id":      "$Category",
    "Value":    {
    "$sum":     "$Value"
    },
    "Messages": {
    "$push":    "$Messages"
    }
    }
    };
    > var project1 = {
    "$project": {
    "Value":    1,
    "Messages": {
    "$cond":    [
    {
    "$eq":  [
    "$Messages",
    [ [ ] ]
    ]
    },
    [ [ null ] ],
    "$Messages"
    ]
    }
    }
    };
    > db.messages.aggregate( group1, project1 )
    { "_id" : 3, "Value" : 100000, "Messages" : [  [  null ] ] }
    { "_id" : 2, "Value" : 11000, "Messages" : [  [  "Msg4" ],  [  "Msg5" ] ] }
    { "_id" : 1, "Value" : 111, "Messages" : [  [  "Msg1",  "Msg2" ],  [ ],  [  "Msg1",  "Msg3" ] ] }

    Ahora descansar dos veces y re-grupo para obtener un solo de los Mensajes de la matriz.

    > var unwind = {"$unwind":"$Messages"};
    > var group2 = {
    $group: {
    "_id":      "$_id", 
    "Value":    {
    "$first":       "$Value"
    }, 
    "Messages": {
    "$addToSet":    "$Messages"
    }
    }
    };
    > var project2 = {
    "$project": {
    "Category": "$_id",
    "_id":      0,
    "Value":    1,
    "Messages": {
    "$cond":    [
    {
    "$eq":  [
    "$Messages",
    [ null ]
    ]
    },
    [ ],
    "$Messages"
    ]
    }
    }
    };
    > db.messages.aggregate(group1, project1, unwind, unwind, group2 ,project2 )
    { "Value" : 111, "Messages" : [  "Msg3",  "Msg2",  "Msg1" ], "Category" : 1 }
    { "Value" : 11000, "Messages" : [  "Msg5",  "Msg4" ], "Category" : 2 }
    { "Value" : 100000, "Messages" : [ ], "Category" : 3 }
    Gracias por los consejos. Casi hace lo que necesito. Sin embargo, hay un caso donde no produce el resultado deseado. Agregados resultado para la Categoría 1 (basado en los documentos que en mi post original) termina con 4 mensajes: [“Msg1”, “Msg2”, “Msg3”, “maniquí”]. No estoy seguro de cómo deshacerte fácilmente de “dummy” para este caso.
    A la derecha – hay una manera de deshacerse de él – voy a actualizar la respuesta
    ok, la respuesta completa ahora con todos los pasos – debe de ser exactamente lo que quieres 🙂
    Esto es exactamente lo que yo buscaba. Muchas gracias por tu ayuda.
    gracias esto es de gran ayuda me podrían ayudar para uno más, el caso de uso en como tengo dos de la matriz de campo en el documento, como se puede decir de los mensajes y etiquetas. Y tengo el mismo comportamiento para los dos campos

    OriginalEl autor Asya Kamsky

  2. 0

    Como ya se ha mencionado en uno de los comentarios, la respuesta más sencilla a la pregunta original es para agregar preserveNullAndEmptyArrays a los $relajarse etapa.

    OriginalEl autor Ruben Stolk

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *