MongoDB group and compute results from multiple fields within same document - mongodb

Can I have your help regarding MongoDB aggregation framework. I trying to build a Premier League Table from following collection of games:
{
"_id" : ObjectId("5b39fec4b5f8df161d259f36"),
"gameWeek" : 1,
"homeTeam" : "Arsenal",
"awayTeam" : "Leicester",
"homeGoals" : 2,
"awayGoals" : 1
}, {
"_id" : ObjectId("5b39ffc2b5f8df161d259f6d"),
"gameWeek" : 2,
"homeTeam" : "Arsenal",
"awayTeam" : "Sunderland",
"homeGoals" : 1,
"awayGoals" : 1
}, {
"_id" : ObjectId("5b39ffe8b5f8df161d259f7f"),
"gameWeek" : 2,
"homeTeam" : "Sunderland",
"awayTeam" : "Manchester United",
"homeGoals" : 1,
"awayGoals" : 1
}, {
"_id" : ObjectId("5b492cbea5aef964f0911cce"),
"gameWeek" : 1,
"homeTeam" : "Manchester United",
"awayTeam" : "Leicester",
"homeGoals" : 0,
"awayGoals" : 1
}
I wish to get following results:
{
"_id" : "Arsenal",
"team" : "Arsenal",
"gamesPlayed" : 2,
"goalsFor" : 3,
"goalsAgainst" : 2,
"goalsDifference" : 1,
"gamesWon" : 1,
"gamesDraw" : 1,
"gamesLost" : 0,
"points" : 4
}, {
"_id" : "Leicester",
"team" : "Leicester",
"gamesPlayed" : 2,
"goalsFor" : 2,
"goalsAgainst" : 2,
"goalsDifference" : 0,
"gamesWon" : 1,
"gamesDraw" : 0,
"gamesLost" : 1,
"points" : 3
}, {
"_id" : "Sunderland",
"team" : "Sunderland",
"gamesPlayed" : 2,
"goalsFor" : 2,
"goalsAgainst" : 2,
"goalsDifference" : 0,
"gamesWon" : 0,
"gamesDraw" : 2,
"gamesLost" : 0,
"points" : 2
}, {
"_id" : "Manchester United",
"team" : "Manchester United",
"gamesPlayed" : 2,
"goalsFor" : 1,
"goalsAgainst" : 2,
"goalsDifference" : -1,
"gamesWon" : 0,
"gamesDraw" : 1,
"gamesLost" : 1,
"points" : 1
}
where:
gamesPlayed - total number of the games played,
goalsFor - total goals made by team,
goalsAgainst - total let in goals,
goalsDifference - 'goalsFor' subtracting 'goalsAgainst'
points - gets calculated scoring 3 points for each won game and 1 point for every draw game.
So far I have following query for building team standing by homeTeam results:
db.football_matches.aggregate([
{
$group: {
_id: "$homeTeam",
gamesPlayed : { $sum: NumberInt(1) },
goalsFor: { $sum: "$homeGoals" },
goalsAgainst: { $sum: "$awayGoals" },
gamesWon: { $sum: { $cond: { if: { $gt: [ "$homeGoals", "$awayGoals" ]}, then: NumberInt(1), else: NumberInt(0) } }},
gamesDraw: { $sum: { $cond: { if: { $eq: [ "$homeGoals", "$awayGoals" ]}, then: NumberInt(1), else: NumberInt(0) } }},
gamesLost: { $sum: { $cond: { if: { $lt: [ "$homeGoals", "$awayGoals" ]}, then: NumberInt(1), else: NumberInt(0) } }}
}
}, {
$project: {
team: "$_id" ,
gamesPlayed: "$gamesPlayed",
goalsFor: "$goalsFor",
goalsAgainst: "$goalsAgainst",
goalsDifference: { $subtract: [ "$goalsFor", "$goalsAgainst"] },
gamesWon: "$gamesWon",
gamesDraw: "$gamesDraw",
gamesLost: "$gamesLost",
points: { $add: [ {$multiply: [ "$gamesWon", NumberInt(3)]}, {$multiply: [ "$gamesDraw", NumberInt(1)]} ]}
}
}, {
$sort: { points: -1, goalsDifference: -1 }
}
])
Theoretically I need to combine following grouping results with another similar group statement where similar action will be perform against awayTeam fields:
{
$group: {
_id: "$awayTeam",
gamesPlayed : { $sum: NumberInt(1) },
goalsFor: { $sum: "$awayGoals" },
goalsAgainst: { $sum: "$homeGoals" },
gamesWon: { $sum: { $cond: { if: { $gt: [ "$awayGoals", "$homeGoals" ]}, then: NumberInt(1), else: NumberInt(0) } }},
gamesDraw: { $sum: { $cond: { if: { $eq: [ "$awayGoals", "$homeGoals" ]}, then: NumberInt(1), else: NumberInt(0) } }},
gamesLost: { $sum: { $cond: { if: { $lt: [ "$awayGoals", "$homeGoals" ]}, then: NumberInt(1), else: NumberInt(0) } }}
}
}
How can I do that? Thank you very much. Please accept my apologies if similar question was asked before.

You can try below aggregation using $facet, $replaceRoot, $unwind, $concatArrays and finally with one more $group stage
db.collection.aggregate([
{ "$facet": {
"first": [
{ "$group": {
"_id": "$homeTeam",
"gamesPlayed": { "$sum": 1 },
"goalsFor": { "$sum": "$homeGoals" },
"goalsAgainst": { "$sum": "$awayGoals" },
"gamesWon": {
"$sum": { "$cond": { "if": { "$gt": [ "$homeGoals", "$awayGoals" ] }, "then": 1, "else": 0 } }
},
"gamesDraw": {
"$sum": { "$cond": { "if": { "$eq": [ "$homeGoals", "$awayGoals" ] }, "then": 1, "else": 0 } }
},
"gamesLost": {
"$sum": { "$cond": { "if": { "$lt": [ "$homeGoals", "$awayGoals" ] }, "then": 1, "else": 0 } }
}
}},
{ "$project": {
"team": "$_id",
"gamesPlayed": "$gamesPlayed",
"goalsFor": "$goalsFor",
"goalsAgainst": "$goalsAgainst",
"goalsDifference": { "$subtract": [ "$goalsFor", "$goalsAgainst" ] },
"gamesWon": "$gamesWon",
"gamesDraw": "$gamesDraw",
"gamesLost": "$gamesLost",
"points": { "$add": [{ "$multiply": [ "$gamesWon", 3 ] }, { "$multiply": [ "$gamesDraw", 1 ] }] }
}},
{ "$sort": { "points": -1, "goalsDifference": -1 } }
],
"second": [
{ "$group": {
"_id": "$awayTeam",
"gamesPlayed": { "$sum": 1 },
"goalsFor": { "$sum": "$awayGoals" },
"goalsAgainst": { "$sum": "$homeGoals" },
"gamesWon": {
"$sum": { "$cond": { "if": { "$gt": [ "$awayGoals", "$homeGoals" ] }, "then": 1, "else": 0 } }
},
"gamesDraw": {
"$sum": { "$cond": { "if": { "$eq": [ "$awayGoals", "$homeGoals" ] }, "then": 1, "else": 0 } }
},
"gamesLost": {
"$sum": { "$cond": { "if": { "$lt": [ "$awayGoals", "$homeGoals" ] }, "then": 1, "else": 0 } }
}
}},
{ "$project": {
"team": "$_id",
"gamesPlayed": "$gamesPlayed",
"goalsFor": "$goalsFor",
"goalsAgainst": "$goalsAgainst",
"goalsDifference": { "$subtract": [ "$goalsFor", "$goalsAgainst" ] },
"gamesWon": "$gamesWon",
"gamesDraw": "$gamesDraw",
"gamesLost": "$gamesLost",
"points": { "$add": [{ "$multiply": [ "$gamesWon",3 ] }, { "$multiply": [ "$gamesDraw",1 ] } ] }
}},
{ "$sort": { "points": -1, "goalsDifference": -1 } }
]
}},
{ "$project": {
"data": {
"$concatArrays": [ "$first", "$second" ]
}
}},
{ "$unwind": "$data" },
{ "$replaceRoot": { "newRoot": "$data" } },
{ "$group": {
"_id": "$_id",
"gamesPlayed": { "$sum": "$gamesPlayed" },
"goalsFor": { "$sum": "$goalsFor" },
"goalsAgainst": { "$sum": "$goalsAgainst" },
"gamesWon": { "$sum": "$gamesWon" },
"gamesDraw": { "$sum": "$gamesDraw" },
"gamesLost": { "$sum": "$gamesLost" }
}}
])

Related

Fill day gaps of two-dimensional timeseries data in MongoDB with aggregate

I have a collection of two-dimensional timeseries data as follows:
[
{
"value" : 9,
"timestamp" : "2020-12-30T02:06:33.000+0000",
"recipeId" : 15
},
{
"value" : 2,
"timestamp" : "2020-12-30T12:04:23.000+0000",
"recipeId" : 102
},
{
"value" : 5,
"timestamp" : "2020-12-30T15:09:23.000+0000",
"recipeId" : 102
},
...
]
The records have a recipeId which is the first level of grouping I'm looking for. All values for a day of a recipe should be summed up. I want an array of timeseries per recipeId. I need the missing days to be filled with a 0. I want this construct to be created for a provided start and end date range.
Some like this for date range of 2020-12-29 to 2020-12-31:
[
[
{
"sum" : 0,
"timestamp" : "2020-12-29",
"recipeId" : 15
},
{
"sum" : 9,
"timestamp" : "2020-12-30",
"recipeId" : 15
},
{
"sum" : 0,
"timestamp" : "2020-12-31",
"recipeId" : 15
},
...
],
[
{
"sum" : 0,
"timestamp" : "2020-12-29",
"recipeId" : 0
},
{
"sum" : 7,
"timestamp" : "2020-12-30",
"recipeId" : 102
},
{
"sum" : 0,
"timestamp" : "2020-12-31",
"recipeId" : 102
},
...
]
]
This is what I currently have and it's only partially solving my requirements. I can't manage to get the last few stages right:
[
{
"$match": {
"timestamp": {
"$gte": "2020-12-29T00:00:00.000Z",
"$lte": "2020-12-31T00:00:00.000Z"
}
}
},
{
"$addFields": {
"timestamp": {
"$dateFromParts": {
"year": { "$year": "$timestamp" },
"month": { "$month": "$timestamp" },
"day": { "$dayOfMonth": "$timestamp" }
}
},
"dateRange": {
"$map": {
"input": {
"$range": [
0,
{
"$trunc": {
"$divide": [
{
"$subtract": [
"2020-12-31T00:00:00.000Z",
"2020-12-29T00:00:00.000Z"
]
},
1000
]
}
},
86400
]
},
"in": {
"$add": [
"2020-12-29T00:00:00.000Z",
{ "$multiply": ["$$this", 1000] }
]
}
}
}
}
},
{ "$unwind": "$dateRange" },
{
"$group": {
"_id": { "date": "$dateRange", "recipeId": "$recipeId" },
"count": {
"$sum": { "$cond": [{ "$eq": ["$dateRange", "$timestamp"] }, 1, 0] }
}
}
},
{
"$group": {
"_id": "$_id.date",
"total": { "$sum": "$count" },
"byRecipeId": {
"$push": {
"k": { "$toString": "$_id.recipeId" },
"v": { "$sum": "$count" }
}
}
}
},
{ "$sort": { "_id": 1 } },
{
"$project": {
"_id": 0,
"timestamp": "$_id",
"total": "$total",
"byRecipeId": {
"$arrayToObject": {
"$filter": { "input": "$byRecipeId", "cond": "$$this.v" }
}
}
}
}
]
which results in:
[
{
"timestamp": "2020-12-29T00:00:00.000Z",
"total": 21,
"byRecipeId": {}
},
{
"timestamp": "2020-12-30T00:00:00.000Z",
"total": 0,
"byRecipeId": {
"15": 9,
"102": 7
}
},
{
"timestamp": "2020-12-31T00:00:00.000Z",
"total": 0,
"byRecipeId": {}
}
]
I'm open to alternative solution of course. For examples I came across this post: https://medium.com/#alexandro.ramr777/fill-missing-values-using-mongodb-aggregation-framework-f011114e83e0 but it doesn't deal with multi-dimensions.
You could use the $redcue function. This code fills the gabs of Minutes for current day. Should be easy to adapt it to give missing Days.
{
$addFields: {
data: {
$reduce: {
input: { $range: [0, 24 * 60] },
initialValue: [],
in: {
$let: {
vars: {
ts: {
$add: [
moment().startOf('day').toDate(),
{ $multiply: ["$$this", 1000 * 60] }
]
}
},
in: {
$concatArrays: [
"$$value",
[{
$cond: {
if: { $in: ["$$ts", "$data.timestamp"] },
then: {
$first: {
$filter: {
input: "$data",
cond: { $eq: ["$$this.timestamp", "$$ts"] }
}
}
},
else: { timestamp: "$$ts", total: 0 }
}
}]
]
}
}
}
}
}
}
}
In my opinion, $reduce is more elegant than $map, however based on my experience the performance is much worse with $reduce.

How to use aggregate in mongodb

I have data like this in mongodb
{
"_id" : 1,
"data" : "ARIN",
"status" : "CLOSED",
"createdDate" : Date("2020-02-16T17:32:28+07:00")
},
{
"_id" : 2,
"source" : "ARIN",
"status" : "NEW",
"createdDate" : Date("2020-02-16T17:32:28+07:00")
},
{
"_id" : 3,
"data" : "APNIC",
"status" : "ONPROGRESS",
"createdDate" : Date("2020-02-17T17:32:28+07:00")
},
{
"_id" : 4,
"data" : "RIPE",
"status" : "NEW",
"createdDate" : Date("2020-02-17T17:32:28+07:00")
}
I want to result like this
{
statusNew : 2,
statusOnProgress : 1,
statusClosed : 1
statusTicketClosedDate1602 : 1,
statusTicketNewdDate1602 : 1,
statusTicketOnProgressDate1602 : 0
}
I have try use group and cond in mongodb, but to no avail. How can I write this query?
You can use this query,
db.collection.aggregate([{
$group: {
_id: null,
statusNew: { $sum: { $cond: [{ "$eq": ["$status", "NEW"] }, 1, 0] } },
statusOnProgress: { $sum: { $cond: [{ "$eq": ["$status", "ONPROGRESS"] }, 1, 0] } },
statusClosed: { $sum: { $cond: [{ "$eq": ["$status", "CLOSED"] }, 1, 0] } },
statusTicketClosedDate1602: {
$sum: {
$cond: [{
$and: [{ "$eq": ["$status", "CLOSED"] },
{ "$gte": ["$createdDate", ISODate("2020-02-16T00:00:00Z")] },
{ "$lt": ["$createdDate", ISODate("2020-02-17T00:00:00Z")] }]
}, 1, 0]
}
},
statusTicketNewdDate1602: {
$sum: {
$cond: [{
$and: [{ "$eq": ["$status", "NEW"] },
{ "$gte": ["$createdDate", ISODate("2020-02-16T00:00:00Z")] },
{ "$lt": ["$createdDate", ISODate("2020-02-17T00:00:00Z")] }]
}, 1, 0]
}
},
statusTicketOnProgressDate1602: {
$sum: {
$cond: [{
$and: [{ "$eq": ["$status", "ONPROGRESS"] },
{ "$gte": ["$createdDate", ISODate("2020-02-16T00:00:00Z")] },
{ "$lt": ["$createdDate", ISODate("2020-02-17T00:00:00Z")] }]
}, 1, 0]
}
}
}
}])

How to add two collections with single aggregation

I am new to MongoDb and would appreciate some help with this query. I wrote the following aggregation pipeline. I wrote the query from collection1 I got the output ("Conventional Energy" : 0.0036) and I wrote the query collection2 I got the output (LastMonthConsumption" : 2.08) but how to add two collection with single aggregation with(LastMonthConsumption" : 2.08 * Conventional Energy" : 0.0036/Conventional Energy" : 0.0036) this is my required output
I have this data in mongodb:
COLLECTION 1:DATA
{
"slcId" : "51",
"clientId" : "1",
"dcuId" : "1",
"type" : "L",
"officeId" : "200-24",
"lampStatus" : "OFF",
"cummulativeKWH" : 133.7,
"powerFactor" : 1.0,
"createDate" : ISODate("2018-09-06T00:01:34.816Z")
},
{
"slcId" : "52",
"clientId" : "1",
"dcuId" : "1",
"type" : "L",
"officeId" : "200-24",
"lampStatus" : "OFF",
"cummulativeKWH" : 133.7,
"powerFactor" : 1.0,
"createDate" : ISODate("2018-09-07T21:01:34.816Z")
}
COLLECTION2:DATA
{
"_class" : "MongoStreetLightMonthlyVo",
"timeId" : ISODate("2018-08-04T16:40:08.817Z"),
"vendor" : "CIMCON",
"slcId" : "123450",
"mongoStreetLightChildVo" : {
"totalConsumptionMtd" : 2.08,
"prevConsumptionMtd" : 3.45,
"perChargeKWH" : 9.85,
}
},
{
"_class" : "MongoStreetLightMonthlyVo",
"timeId" : ISODate("2018-09-04T16:40:08.817Z"),
"vendor" : "CIMCON",
"slcId" : "123450",
"mongoStreetLightChildVo" : {
"totalConsumptionMtd" : 2.08,
"prevConsumptionMtd" : 3.45,
"perChargeKWH" : 9.85,
}
}
Collection1:
db.collection1.aggregate([
{ $match:{"type" : "L"}},
{
$count: "TOTAL_Lights"
},
{ "$project": {
"Conventional Energy": {
"$divide": [
{ "$multiply": [
{ "$multiply": [ "$TOTAL_Lights" ,0.12 ] },
]},
1000
]
}
}},
])
output: {"Conventional Energy" : 0.0036}
Collection2:
db.collection2.aggregate(
[
// Stage 1
{
$group: {
_id:{year:{$year:"$timeId"},month:{$month:"$timeId"} },
LastMonthConsumption : {$sum:"$mongoStreetLightChildVo.totalConsumptionMtd"},
}
},
{
$redact: {
$cond: { if: { $and:[
{$eq: [ "$_id.year", {$year:new Date()} ]},
{$eq: [-1, {$subtract:[ "$_id.month", {$month:new Date()} ]}]}
]},
then: "$$KEEP",
else: "$$PRUNE"
}
}
},
{$project:{
_id:0,
LastMonthConsumption :1
}
}
]
);
output:{
"LastMonthConsumption" : 2.08
}
Expected output:
LastMonthConsumption - Conventional Energy/Conventional Energy*100
You can try below aggregation
db.collection2.aggregate([
{ "$group": {
"_id": { "year": { "$year": "$timeId" }, "month": { "$month": "$timeId" }},
"LastMonthConsumption": { "$sum": "$mongoStreetLightChildVo.totalConsumptionMtd" }
}},
{ "$redact": {
"$cond": {
"if": {
"$and": [
{ "$eq": ["$_id.year", { "$year": new Date() }] },
{ "$eq": [-1, { "$subtract": ["$_id.month", { "$month": new Date() }] }]
}
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$lookup": {
"from": "collection1",
"pipeline": [
{ "$match": { "type": "L" } },
{ "$count": "TOTAL_Lights" },
{ "$project": {
"ConventionalEnergy": {
"$divide": [{ "$multiply": [{ "$multiply": ["$TOTAL_Lights", 0.12] }] }, 1000]
}
}}
],
"as": "ConventionalEnergy"
}},
{ "$project": {
"_id": 0,
"totalConsumption": {
"$multiply": [
{
"$divide": [
{
"$subtract": [
"$LastMonthConsumption",
{ "$arrayElemAt": ["$ConventionalEnergy.ConventionalEnergy", 0] }
]
},
{ "$arrayElemAt": ["$ConventionalEnergy.ConventionalEnergy", 0] }
]
},
100
]
}
}}
])

MongoDB aggregate multiple group by top fields and array fields

My collection will look like this,
{
"_id" : ObjectId("591c5971240033283736860a"),
"status" : "Done",
"createdDate" : ISODate("2017-05-17T14:09:20.653Z")
"communications" : [
{
"communicationUUID" : "df07948e-4a14-468e-beb1-db55ff72b215",
"communicationType" : "CALL",
"recipientId" : 12345,
"createdDate" : ISODate("2017-05-18T14:09:20.653Z")
"callResponse" : {
"Status" : "completed",
"id" : "dsd45554545ds92a9bd2c12e0e6436d",
}
}
]}
{
"_id" : ObjectId("45sdsd59124003345121450a"),
"status" : "ToDo",
"createdDate" : ISODate("2017-05-17T14:09:20.653Z")
"communications" : [
{
"communicationUUID" : "45sds55-4a14-468e-beb1-db55ff72b215",
"communicationType" : "CALL",
"recipientId" : 1234,
"createdDate" : ISODate("2017-05-18T14:09:20.653Z")
"callResponse" : {
"Status" : "completed",
"id" : "84fe862f1924455dsds5556436d",
}
}
]}
Currently I am writing two aggregate query to achieve my requirement and my query will be below
db.collection.aggregate(
{ $project: {
dayMonthYear: { $dateToString: { format: "%d/%m/%Y", date: "$createdDate" } },
status: 1,
}},
{ $group: {
_id: "$dayMonthYear",
Pending: { $sum: { $cond : [{ $eq : ["$status", "ToDo"]}, 1, 0]} },
InProgress: { $sum: { $cond : [{ $eq : ["$status", "InProgress"]}, 1, 0]} },
Done: { $sum: { $cond : [{ $eq : ["$status", "Done"]}, 1, 0]} },
Total: { $sum: 1 }
}}
My output will be,
{"_id" : "17/05/2017", "Pending" : 1.0, "InProgress" : 0.0, "Done" : 1.0, "Total" : 2.0 }
Using above query I can able to get count but I need to find the count based on communication Status too so I am writing one more query to achieve,
db.collection.aggregate(
{"$unwind":"$communications"},
{ $project: {
dayMonthYear: { $dateToString: { format: "%d/%m/%Y", date: "$createdDate" } },
communications: 1
}},
{ "$group": {
_id: "$dayMonthYear",
"total_call": { $sum: { $cond : [{ $or : [ { $eq: [ "$communications.callResponse.Status", "failed"] },
{ $eq: [ "$communications.callResponse.Status", "busy"] },
{ $eq: [ "$communications.callResponse.Status", "completed"] },
{ $eq: [ "$communications.callResponse.Status", "no-answer"] }
]}, 1, 0 ] }},
"engaged": { $addToSet: { $cond : [{ $eq : ["$communications.callResponse.Status", "completed"]},
"$communications.recipientId", "null" ]} },
"not_engaged": { $addToSet: { $cond: [{ $or : [ { $eq: [ "$communications.callResponse.Status", "failed"] },
{ $eq: [ "$communications.callResponse.Status", "busy"] },
{ $eq: [ "$communications.callResponse.Status", "no-answer"] } ]},
"$communications.recipientId", "null" ] }}
}},
{ "$project": {
"_id": 1,
"total_call": 1,
"engaged": { "$setDifference": [ "$ngaged", ["null"] ] },
"not_engaged": { "$setDifference": [ "$not_engaged", ["null"] ] },
}},
{ "$project": {
"total_call": 1,
"engaged": { "$size": "$engaged" },
"not_engaged": { "$size": { "$setDifference": [ "$not_engaged", "$engaged" ] }},
}})
My output will be,
{"_id" : "18/05/2017", "total_call" : 2.0, "engaged" : 2, "not_engaged" : 0}
Using above query I can able to get count but I want to achieve it in single query
I am looking for output like
{"_id":"17/05/2017", "Pending" : 1.0, "InProgress" : 0.0, "Done" : 1.0, "total_call" : 0, "engaged" : 0, "not_engaged" : 0}
{"_id":"18/05/2017", "Pending" : 0.0, "InProgress" : 0.0, "Done" : 0.0, "total_call" : 2, "engaged" : 2, "not_engaged" : 0}
Can anyone suggest or provide me good way to get above result.
You can use $concatArrays to merge the status& createdDate documents followed by $group to count the occurrences.
db.collection.aggregate([
{
"$project": {
"statusandcreateddate": {
"$concatArrays": [
[
{
"status": "$status",
"createdDate": "$createdDate"
}
],
{
"$map": {
"input": "$communications",
"as": "l",
"in": {
"status": "$$l.callResponse.Status",
"createdDate": "$$l.createdDate"
}
}
}
]
}
}
},
{
"$unwind": "$statusandcreateddate"
},
{
"$group": {
"_id": {
"$dateToString": {
"format": "%d/%m/%Y",
"date": "$statusandcreateddate.createdDate"
}
},
"total_call": {
"$sum": {
"$cond": [
{
"$or": [
{
"$eq": [
"$statusandcreateddate.status",
"failed"
]
},
{
"$eq": [
"$statusandcreateddate.status",
"busy"
]
},
{
"$eq": [
"$statusandcreateddate.status",
"completed"
]
},
{
"$eq": [
"$statusandcreateddate.status",
"no-answer"
]
}
]
},
1,
0
]
}
},
"engaged": {
"$sum": {
"$cond": [
{
"$eq": [
"$statusandcreateddate.status",
"completed"
]
},
1,
0
]
}
},
"not_engaged": {
"$sum": {
"$cond": [
{
"$or": [
{
"$eq": [
"$statusandcreateddate.status",
"failed"
]
},
{
"$eq": [
"$statusandcreateddate.status",
"busy"
]
},
{
"$eq": [
"$statusandcreateddate.status",
"no-answer"
]
}
]
},
1,
0
]
}
},
"Pending": {
"$sum": {
"$cond": [
{
"$eq": [
"$statusandcreateddate.status",
"ToDo"
]
},
1,
0
]
}
},
"InProgress": {
"$sum": {
"$cond": [
{
"$eq": [
"$statusandcreateddate.status",
"InProgress"
]
},
1,
0
]
}
},
"Done": {
"$sum": {
"$cond": [
{
"$eq": [
"$statusandcreateddate.status",
"Done"
]
},
1,
0
]
}
}
}
}
])

$push and $sum with the aggregation framework on sub-documents

I've a data as follows:
{
"_id" : ObjectId("55d4410544c96d6f6578f893"),
"executionProject" : "Project1",
"suiteList" : [
{
"suiteName": "Suite1",
"suiteStatus" : "PASS",
},
{
"suiteName": "Suite2",
"suiteStatus" : "FAIL",
},
{
"suiteName": "Suite3",
"suiteStatus" : "PASS",
}
],
"runEndTime" : ISODate("2015-08-19T08:40:47.049Z")
}
{
"_id" : ObjectId("55d4410544c96d6f6578f894"),
"executionProject" : "Project1",
"suiteList" : [
{
"suiteName": "Suite1",
"suiteStatus" : "PASS",
},
{
"suiteName": "Suite2",
"suiteStatus" : "FAIL",
},
{
"suiteName": "Suite3",
"suiteStatus" : "FAIL",
}
],
"runEndTime" : ISODate("2015-08-19T08:50:47.049Z")
}
And I was trying to get the result like this:
{
"executionProject": "Project1",
"data": [
{
"date": "2015-08-19 08:40:47",
"suitePass": 2,
"suiteFail": 1
},
{
"date": "2015-08-19 08:50:47",
"suitePass": 1,
"suiteFail": 2
}
]
}
Here I'm trying to group by executionProject and push the runEndTime and the pass and fail counts of suites to the result.
I tried this, but giving me wrong way of projection:
db.testruns.aggregate([
{
$project: {
executionProject: "$executionProject",
runEndTime: "$runEndTime",
suiteList: "$suiteList"
}
},
{
$unwind: "$suiteList"
},
{
$group: {
_id: "$executionProject",
runEndTime: {
$addToSet: "$runEndTime"
},
suite_pass: {
$sum: {
$cond: {
"if": {
$eq: ["$suiteList.suiteStatus", "PASS"]
},
"then": 1,
"else": 0
}
}
}
}
},
{
$group: {
_id: "$_id",
runEndTime: { $push: {runTime: "$runEndTime", suite_pass: "$suite_pass"} }
}
},
{
$project: {
executionProject: "$_id",
runEndTime: "$runEndTime",
_id: 0
}
}
]);
First you need to group by the document to get the suite totals, then you add to the array as you group on the project. Also don't forget to "sort" if you want things in order:
[
{ "$unwind": "$suiteList" },
{ "$group": {
"_id": "$_id",
"executionProject": { "$first": "$executionProject" },
"suite-pass": {
"$sum": {
"$cond": [
{ "$eq": [ "$suiteList.suiteStatus", "PASS" ] },
1,
0
]
}
},
"suite-fail": {
"$sum": {
"$cond": [
{ "$eq": [ "$suiteList.suiteStatus", "FAIL" ] },
1,
0
]
}
},
"date": { "$first": "$runEndTime" }
}},
{ "$sort": { "executionProject": 1, "date": 1 } },
{ "$group": {
"_id": "$executionProject",
"data": {
"$push": {
"suite-pass": "$suite-pass",
"suite-fail": "$suite-fail",
"date": "$date"
}
}
}}
]
Produces:
{
"_id" : "Project1",
"data" : [
{
"suite-pass" : 2,
"suite-fail" : 1,
"date" : ISODate("2015-08-19T08:40:47.049Z")
},
{
"suite-pass" : 1,
"suite-fail" : 2,
"date" : ISODate("2015-08-19T08:50:47.049Z")
}
]
}