what tutorial replicated replicacion replica allow mongodb mongodb-query aggregation-framework

tutorial - Agregado de MongoDB dentro de la agrupación diaria



sharding mongodb (3)

Tengo algunos documentos en mongo que se parecen a esto:

{ _id : ObjectId("..."), "make" : "Nissan", .. }, { _id : ObjectId("..."), "make" : "Nissan", "saleDate" : ISODate("2013-04-10T12:39:50.676Z"), .. }

Idealmente, me gustaría poder contar, por marca, el número de vehículos vendidos por día. Me gustaría ver hoy o una ventana como hoy en los últimos siete días.

Pude lograr la vista diaria con un código feo

db.inventory.aggregate( { $match : { "saleDate" : { $gte: ISODate("2013-04-10T00:00:00.000Z"), $lt: ISODate("2013-04-11T00:00:00.000Z") } } } , { $group : { _id : { make : "$make", saleDayOfMonth : { $dayOfMonth : "$saleDate" } }, cnt : { $sum : 1 } } } )

Que luego arroja los resultados

{ "result" : [ { "_id" : { "make" : "Nissan", "saleDayOfMonth" : 10 }, "cnt" : 2 }, { "_id" : { "make" : "Toyota", "saleDayOfMonth" : 10 }, "cnt" : 4 }, ], "ok" : 1 }

Así que está bien, pero preferiría no tener que cambiar los dos valores de fecha y hora en la consulta. Luego, como mencioné anteriormente, me gustaría poder ejecutar esta consulta (nuevamente, sin tener que modificarla cada vez) y ver los mismos resultados agrupados por día durante la última semana.

Ah, y aquí están los datos de muestra que he estado usando para la consulta

db.inventory.save({"make" : "Nissan","saleDate" : ISODate("2013-04-10T12:39:50.676Z")}); db.inventory.save({"make" : "Nissan"}); db.inventory.save({"make" : "Nissan","saleDate" : ISODate("2013-04-10T11:39:50.676Z")}); db.inventory.save({"make" : "Toyota","saleDate" : ISODate("2013-04-09T11:39:50.676Z")}); db.inventory.save({"make" : "Toyota","saleDate" : ISODate("2013-04-10T11:38:50.676Z")}); db.inventory.save({"make" : "Toyota","saleDate" : ISODate("2013-04-10T11:37:50.676Z")}); db.inventory.save({"make" : "Toyota","saleDate" : ISODate("2013-04-10T11:36:50.676Z")}); db.inventory.save({"make" : "Toyota","saleDate" : ISODate("2013-04-10T11:35:50.676Z")});

Gracias de antemano, Kevin


En Mongo 2.8 RC2 hay un nuevo operador de agregación de datos: $ dateToString que se puede usar para agrupar por un día y simplemente tener un "AAAA-MM-DD" en el resultado:

Ejemplo de la documentación:

db.sales.aggregate( [ { $project: { yearMonthDay: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, time: { $dateToString: { format: "%H:%M:%S:%L", date: "$date" } } } } ] )

resultará en:

{ "_id" : 1, "yearMonthDay" : "2014-01-01", "time" : "08:15:39:736" }


Es posible que desee echar un vistazo a mi entrada de blog sobre cómo lidiar con varias manipulaciones de fecha en el Marco de Agregación aquí .

Lo que puede hacer es usar $project phase para truncar sus fechas a resolución diaria y luego ejecutar la agregación en todo el conjunto de datos (o solo una parte) y agregar por fecha y marca.

Con sus datos de muestra, suponga que desea saber cuántos vehículos vendió por marca, por fecha este año:

match={"$match" : { "saleDate" : { "$gt" : new Date(2013,0,1) } } }; proj1={"$project" : { "_id" : 0, "saleDate" : 1, "make" : 1, "h" : { "$hour" : "$saleDate" }, "m" : { "$minute" : "$saleDate" }, "s" : { "$second" : "$saleDate" }, "ml" : { "$millisecond" : "$saleDate" } } }; proj2={"$project" : { "_id" : 0, "make" : 1, "saleDate" : { "$subtract" : [ "$saleDate", { "$add" : [ "$ml", { "$multiply" : [ "$s", 1000 ] }, { "$multiply" : [ "$m", 60, 1000 ] }, { "$multiply" : [ "$h", 60, 60, 1000 ] } ] } ] } } }; group={"$group" : { "_id" : { "m" : "$make", "d" : "$saleDate" }, "count" : { "$sum" : 1 } } };

Ahora ejecutar la agregación te da:

db.inventory.aggregate(match, proj1, proj2, group) { "result" : [ { "_id" : { "m" : "Toyota", "d" : ISODate("2013-04-10T00:00:00Z") }, "count" : 4 }, { "_id" : { "m" : "Toyota", "d" : ISODate("2013-04-09T00:00:00Z") }, "count" : 1 }, { "_id" : { "m" : "Nissan", "d" : ISODate("2013-04-10T00:00:00Z") }, "count" : 2 } ], "ok" : 1 }

Puede agregar otra fase de {$ project} para completar el resultado y puede agregar un paso {$ sort}, pero básicamente para cada fecha, para cada marca obtendrá un recuento de cuántos se vendieron.


Me gusta la respuesta del usuario1083621 , pero ese método causa algunas limitaciones en las siguientes operaciones con este campo, porque no puede usarlo como campo de fecha en (por ejemplo) las siguientes etapas de la agregación de agregación. No puede comparar ni usar ninguna operación de agregación de fecha y después de la agregación tendrá cadenas (!). Todo eso se puede resolver proyectando el campo de fecha original, pero en ese caso tendrá algunas dificultades para retenerlo a través de la etapa de agrupamiento. Y, después de todo, a veces solo quieres manipular con el comienzo del día, no con un día arbitrario. Así que aquí está mi método:

{''$project'': { ''start_of_day'': {''$subtract'': [ ''$date'', {''$add'': [ {''$multiply'': [{''$hour'': ''$date''}, 3600000]}, {''$multiply'': [{''$minute'': ''$date''}, 60000]}, {''$multiply'': [{''$second'': ''$date''}, 1000]}, {''$millisecond'': ''$date''} ]} ]}, }}

Te da esto:

{ "start_of_day" : ISODate("2015-12-03T00:00:00.000Z") }, { "start_of_day" : ISODate("2015-12-04T00:00:00.000Z") }

No puedo decir si es más rápido que el método de user1083621 .