Tengo que hacer un especial de mongoDB consulta.

Tengo una colección de documentos como estos:

{
"_id" : ObjectId("53c7fd86d624b06abc76e8f6"),
"works" : [ 
{
"code" : "A001",
"name" : "Cambiar bombilla",
"orderId" : "53c7fd86d624b06abc76e8f6",
"price" : 1400,
"ID" : 1,
"lazyLoaded" : true,
"status" : 0,
"Date" : ISODate("2014-07-21T10:31:55.063Z"),
"TechnicianId" : "538efd918163b19307c59e8e",
"_id" : ObjectId("53ccec1bf2bf4d5952b2f205")
}, 
{
"code" : "A005",
"name" : "Cambiar bombilla 5",
"price" : 1050,
"type" : "Bombillas",
"TechnicianId" : "5383577a994be8b9a9e3f01e",
"_id" : ObjectId("53ccfdbdf2bf4d5952b2f206")
}, 
{
"code" : "A004",
"name" : "Cambiar bombilla 4",
"price" : 1010,
"type" : "Bombillas",
"TechnicianId" : "5383577a994be8b9a9e3f01e",
"date" : "2014-07-21T11:50:52.702Z",
"orderId" : "53c7fd86d624b06abc76e8f6",
"_id" : ObjectId("53ccfe9c109c100000ad688a")
}, 
{
"code" : "A002",
"name" : "Cambiar bombilla 2",
"price" : 1030,
"type" : "Bombillas",
"TechnicianId" : "5383577a994be8b9a9e3f01e",
"date" : "2014-07-21T11:57:37.065Z",
"orderId" : "53c7fd86d624b06abc76e8f6",
"_id" : ObjectId("53cd0036109c100000ad688b")
}, 
{
"code" : "A003",
"name" : "Cambiar bombilla 3",
"price" : 1050,
"type" : "Bombillas",
"TechnicianId" : "5383577a994be8b9a9e3f01e",
"date" : "2014-07-21T11:59:35.586Z",
"orderId" : "53c7fd86d624b06abc76e8f6",
"_id" : ObjectId("53cd00a7109c100000ad688c")
}
],
"Items" : [ 
{
"_id" : "534ba71f394835a7e51dd938",
"total":50
"qty" : 2
}, 
{
"_id" : "534664b081362062015d1b77",
"qty" : 2,
"total":30
}
]}

Ahora, quiero hacer una consulta para obtener las obras con TechnicianId=5383577a994be8b9a9e3f01e , la suma de los «precios» para estas obras de deducir de la suma de los elementos.total, la cantidad del total de las obras de estos documentos de deducir de la suma de los elementos.total.

Para este ejemplo quiero algo como esto:

{
"result" : [ 
{
"_id" : ObjectId("53c7fd86d624b06abc76e8f6"),
"works.totalsumfortech" : 1050+1010+1030+1050 - (50+30),//Sum of works of this technicianId deducting the items.total qty
"works.total":1400+1050+1010+1030+1050-(50+30)//Summ of all works of document deducting the items.total qty
}
],
"ok" : 1
}

Esta es mi consulta, pero no obtengo el resultado esperado..

db.orders.aggregate([
{ "$match": {
"$and": [
{"OrderState": {$in:['Review','Archived']}},
{'works.TechnicianId':'5383577a994be8b9a9e3f01e'}
]
}},
{$group: {
_id: "$_id",
'total': {$subtract:[{$sum: { $cond: [ { $eq: [ "$works.TechnicianId", "5383577a994be8b9a9e3f01e" ] } , 2, 1 ]},{$sum: '$Items.total'}]
'total': {$subtract:[{$sum: '$works.price'},{$sum: '$Items.total'}]
}
}]);
  • Usted necesidad de utilizar $unwind en las matrices de primera. Se han preguntado cosas similares antes.
  • Sí, lo sé, pero mi pregunta en la suma con el condicional, no sé si puedo hacer esto.
  • Si «saber», su declaración mostraría un $unwind. No. Esta es la razón por la que no funciona.
InformationsquelleAutor colymore | 2014-07-23

1 Comentario

  1. 10

    Moderno

    Esto en realidad es mucho más fácil con las modernas versiones de MongoDB. En el caso particular no es real «agregación» a través de documentos, aunque hay una reducción significativa en los datos devueltos y «agregación dentro del documento» a ser aplicado.

    La moderna esto permite que este tipo de remodelación y selección de datos en matrices sin necesidad de recurrir a $relajarse y $group en el fin del proceso:

    db.getCollection('orders').aggregate([
    { "$match": {
    //"OrderState": { "$in":["Review","Archived"]},
    "works.TechnicianId":"5383577a994be8b9a9e3f01e"
    }},
    { "$project": {
    "works": {
    "$let": {
    "vars": {
    "techTotal": {
    "$sum": {
    "$map": {
    "input": { 
    "$filter": {
    "input": "$works",
    "cond": {
    "$eq": [
    "$$this.TechnicianId",
    "5383577a994be8b9a9e3f01e"
    ]
    }
    }
    },
    "in": "$$this.price"
    }    
    }
    },
    "items_total": { "$sum": "$Items.total" },
    "worksTotal": { "$sum": "$works.price" }
    },
    "in": {
    "totalSumForTech": {
    "$subtract": [ "$$techTotal", "$$items_total" ]
    },
    "total": {
    "$subtract": [ "$$worksTotal", "$$items_total" ]
    }
    }
    }
    }
    }}
    ])

    Los cambios desde pidió originalmente se que $suma acepta una «matriz» como entrada cuando se utiliza en un $proyecto o similar etapa de contexto además de la función tradicional como un acumulador. Así que en lugar de «desenrollar» una matriz, puede hacer cosas como { "$sum": "$Items.total" } que retuns una matriz de valores de la propiedad especificada por el interior de la notación y, a continuación, «reduce» los valores a través de $suma. Eso es una gran mejora sobre la que es propia.

    Otras mejoras son $map y $filter. Donde este último se aplica con el fin de devolver sólo la coincidencia de las entradas de una matriz a una condición determinada, y para el ex permite la «remodelación» del contenido de la matriz. Ambos son métodos comunes en otros lenguajes de programación para lidiar con las matrices y, básicamente, la misma función aquí.

    Esto significa que usted puede extraer el "price" valores de la "works" matriz de coincidencia de que el técnico como es necesario y, a continuación, el total de los que utilizan $suma como un «conjunto de valores» de la misma manera como se describió anteriormente.

    La otra incorporación es $let, lo que permite un bloque que se declaró con «variables» para el uso dentro de ese bloque. En este caso podemos calcular los «totales» de las matrices y, a continuación, aplicar $restar de los valores calculados con el fin de llegar al resultado final.

    La ventaja respecto a las versiones anteriores es que usted puede hacer esto sin la separación de la agregación de canalización de las etapas. Y, por supuesto, la $$items_total puede ser utilizado en lugar de la repetición de la declaración completa de calcular. También el general de la separación de los cálculos que hace el último bloque de salida un poco más fácil de leer. Así que es realmente «el uso de variables» en mucho la misma manera que en la programación regular.

    La gran ganancia de aquí es que esto se convierte en simplemente $match y $proyecto, y no de toda la cadena de canalización de las etapas sólo para llegar a la final calcula el resultado de cada documento.


    Original

    Como se indicó anteriormente, usted necesidad utilizar $relajarse cuando se trabaja con matrices en MongoDB agregación. Las operaciones de agregación no funcionan en cada elemento de la matriz a menos que usted haga esto.

    Otros problemas aquí que dentro de la $group fase de canalización todo el «nivel superior» las operaciones deben ser el grupo de operadores de agregación. Cosas que no son como $restar no están permitidos, por lo que necesita para hacer esas operaciones, ya sea dentro de algo como $suma donde es posible, o en otra fase de canalización:

    db.orders.aggregate([
    //Match documents "and" is implied in MongoDB. Not required unless
    //against the same field
    { "$match": {
    "OrderState": { "$in":["Review","Archived"]},
    "works.TechnicianId":"5383577a994be8b9a9e3f01e"
    }},
    //Unwind Items first
    { "$unwind": "$Items" },
    //Group to get that total
    { "$group": {
    "_id": "$_id",
    "works": { "$first": "$works" },
    "items_total": { "$sum": "$Items.total" }
    }},
    //Unwind works to "de-normalize"
    { "$unwind": "$works" },
    //Group conditionally on "TechnicianId" and the full total
    { "$group": {
    "_id": "$_id",
    "techTotal": {
    "$sum": {
    "$cond": [ 
    { "$eq": [ 
    "$works.TechnicianId", 
    "5383577a994be8b9a9e3f01e"
    ]},
    "$works.price",
    0 
    ]
    }
    },
    "worksTotal": { "$sum": "$works.price" },
    "items_total": { "$first": "$items_total" }
    }},
    //Project to do math and other re-shaping
    { "$project": {
    "works": {
    "totalSumForTech": {
    "$subtract": [ "$techTotal", "$items_total" ]
    },
    "total": {
    "$subtract": [ "$worksTotal", "$items_total" ]
    }
    }
    }}
    ])

    En el documento de muestra (aunque tengo que soltar el $match ya que no existen datos en la muestra ) los resultados son:

    {
    "_id" : ObjectId("53c7fd86d624b06abc76e8f6"),
    "works" : {
    "totalSumForTech" : 4060,
    "total" : 5460
    }
    }
    • Wow, pensé que su más fácil..es muy difícil. Mi principal problema de su no sé usar el relajarse correcly.
    • Ahora tienes un ejemplo que debe ser capaz de reflejar en otra situación en la que usted está tratando de trabajar con los valores de las matrices.
    • Sí, lo voy a hacer.Gracias

Dejar respuesta

Please enter your comment!
Please enter your name here