Mongodb: Agrupe por elemento y muestre el recuento de sub-documentos según la condición y ordene el documento por fecha

Tengo colecciones de documentos como a continuación:

{ "_id" : ObjectId("55d4410544c96d6f6578f893"), "executionProject" : "Project1", "suiteList" : [ { "suiteStatus" : "PASS", } ], "runEndTime" : ISODate("2015-08-19T08:40:47.049Z"), "runStartTime" : ISODate("2015-08-19T08:40:37.621Z"), "runStatus" : "PASS", "__v" : 1 } { "_id" : ObjectId("55d44eb4c0422e7b8bffe76b"), "executionProject" : "Project1", "suiteList" : [ { "suiteStatus" : "PASS", } ], "runEndTime" : ISODate("2015-08-19T09:39:13.528Z"), "runStartTime" : ISODate("2015-08-19T09:39:00.406Z"), "runStatus" : "PASS", "__v" : 1 } { "_id" : ObjectId("55d44f0bc0422e7b8bffe76f"), "executionProject" : "Project1", "suiteList" : [ { "suiteStatus" : "FAIL", } ], "runEndTime" : ISODate("2015-08-19T09:46:31.108Z"), "runStartTime" : ISODate("2015-08-19T09:40:27.377Z"), "runStatus" : "PASS", "__v" : 1 } { "_id" : ObjectId("55d463d0c0422e7b8bffe789"), "executionProject" : "Project2", "suiteList" : [ { "suiteStatus" : "FAIL" }, { "suiteStatus" : "PASS" } ], "runEndTime" : ISODate("2015-08-19T11:09:52.537Z"), "runStartTime" : ISODate("2015-08-19T11:09:04.539Z"), "runStatus" : "FAIL", "__v" : 1 } { "_id" : ObjectId("55d464ebc0422e7b8bffe7c2"), "executionProject" : "Project3", "suiteList" : [ { "suiteStatus" : "FAIL" } ], "runEndTime" : ISODate("2015-08-19T11:18:41.460Z"), "runStartTime" : ISODate("2015-08-19T11:13:47.268Z"), "runStatus" : "FAIL", "__v" : 10 } 

Y estoy esperando la salida de la siguiente manera:

 [ { "executionProject": "Project1", "suite-pass": 0, "suite-fail": 1, "runEndTime": ISODate("2015-08-19T09:46:31.108Z") }, { "executionProject": "Project2", "suite-pass": 1, "suite-fail": 1, "runEndTime": ISODate("2015-08-19T11:09:52.537Z") }, { "executionProject": "Project3", "suite-pass": 0, "suite-fail": 1, "runEndTime": ISODate("2015-08-19T11:18:41.460Z") }, ] 

Quiero agrupar por proyecto y orden por runEndTime y mostrar los conteos de pasadas y fallas de suiteList.

Sé cómo obtener los recuentos de pases y fallos de todas las ejecuciones, pero no estoy seguro de cómo puedo agrupar y ordenar. Por favor ayuda

El marco de agregación con el operador $cond parece ser lo que está buscando:

  Model.aggregate([ { "$unwind": "$suiteList" }, { "$group": { "_id": "$executionProject", "suite-pass": { "$sum": { "$cond": [ { "$eq": [ "$suiteList.suiteStatus", "PASS" ] }, 1, 0 ] } }, "suite-fail": { "$sum": { "$cond": [ { "$eq": [ "$suiteList.suiteStatus", "FAIL" ] }, 1, 0 ] } }, "runEndTime": { "$max": "$runEndTime" } }}, { "$sort": { "runEndTime": 1 }} ],function(err,result) { }); 

Esto prueba condicionalmente los valores para “PASS” o “FAIL” y los devuelve al acumulador de $sum debajo de $group . De la misma manera, toma el valor $max para la fecha relevante por documentos agrupados.

Lo último es solo $sort por esa fecha


Si la “suiteList” en realidad solo contendrá un “PASS” y un “FAIL” al máximo, entonces es probable que pueda escapar sin siquiera usar $unwind en la matriz:

  Model.aggregate( [ { "$group": { "_id": "$executionProject", "suite-pass": { "$sum": { "$cond": [ { "$anyElementTrue": { "$map": { "input": "$suiteList", "as": "suite", "in": { "$eq": [ "$$suite.suiteStatus", "PASS" ] } } }}, 1, 0 ] } }, "suite-fail": { "$sum": { "$cond": [ { "$anyElementTrue": { "$map": { "input": "$suiteList", "as": "suite", "in": { "$eq": [ "$$suite.suiteStatus", "FAIL" ] } } }}, 1, 0 ] } }, "runEndTime": { "$max": "$runEndTime" } }}, { "$sort": { "runEndTime": 1 }} ], function(err,results) { } ) 

El $map y $anyElementTrue allí pueden probar de forma similar las condiciones en la matriz que coinciden en el lugar en el que se deben contar. Por lo tanto, si el “número de coincidencias” por documento no importa, entonces esto está bien.

En sus datos aquí que cumplen esas condiciones, ambos producen el mismo resultado:

 { "_id" : "Project1", "suite-pass" : 2, "suite-fail" : 1, "runEndTime" : ISODate("2015-08-19T09:46:31.108Z") } { "_id" : "Project2", "suite-pass" : 1, "suite-fail" : 1, "runEndTime" : ISODate("2015-08-19T11:09:52.537Z") } { "_id" : "Project3", "suite-pass" : 0, "suite-fail" : 1, "runEndTime" : ISODate("2015-08-19T11:18:41.460Z") } 

Para obtener los “últimos” artículos, simplemente $sort primero y reemplaza los sumdores de $sum por el $last acumulador de $last :

  Model.aggregate( [ { "$sort": { "runEndTime": 1 } }, { "$group": { "_id": "$executionProject", "suite-pass": { "$last": { "$cond": [ { "$anyElementTrue": { "$map": { "input": "$suiteList", "as": "suite", "in": { "$eq": [ "$$suite.suiteStatus", "PASS" ] } } }}, 1, 0 ] } }, "suite-fail": { "$last": { "$cond": [ { "$anyElementTrue": { "$map": { "input": "$suiteList", "as": "suite", "in": { "$eq": [ "$$suite.suiteStatus", "FAIL" ] } } }}, 1, 0 ] } }, "runEndTime": { "$last": "$runEndTime" } }}, { "$sort": { "runEndTime": 1 } } ], function(err,results) { } ); 

Lo que produce:

 { "_id" : "Project1", "suite-pass" : 0, "suite-fail" : 1, "runEndTime" : ISODate("2015-08-19T09:46:31.108Z") } { "_id" : "Project2", "suite-pass" : 1, "suite-fail" : 1, "runEndTime" : ISODate("2015-08-19T11:09:52.537Z") } { "_id" : "Project3", "suite-pass" : 0, "suite-fail" : 1, "runEndTime" : ISODate("2015-08-19T11:18:41.460Z") }