How to use aggregate in mongodb - 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]
}
}
}
}])

Related

Mongo DB aggregation with $project and $filter: $add and $subtract return null

So I'm running a pretty big aggregation query in mongo shell (just for testing purpose)
in my last $project step, i use $filter to select a range of elements.
$filter: {
"input": "$users",
"as": "users",
"cond": {
$and: [
{
$lte: [
"$$users.ranking",
{$add: ["$myUser[0].ranking", 5]}
]
},
{
$gte: [
"$$users.ranking",
{$subtract: ["$myUser[0].ranking", 5]}
]
}
]
}
}
$subtract and $add both return null, any idea how i get it correct?
MongoVersion: 3.6.3, running in a docker container using the mongo 3.6.3 image.
Correct output should be:
"users" : [
{
"_id" : ObjectId("5ba3c2089a3a3e26a859f11b"),
"sgId" : ObjectId("5b76c1040c3aa5000559e6b3"),
"score" : 30,
"ranking" : NumberLong("0")
},
{
"_id" : ObjectId("5ba3c1d89a3a3e26a859f11a"),
"sgId" : ObjectId("5b76c1000c3aa500060e0fd2"),
"score" : 20,
"ranking" : NumberLong("1")
},
{
"_id" : ObjectId("5ba4fa3b71936b33e46569b9"),
"sgId" : ObjectId("5b76c8a3f7d606000566b652"),
"score" : 10,
"ranking" : NumberLong("2")
},
{
"_id" : ObjectId("5ba4fa4c71936b33e46569ba"),
"sgId" : ObjectId("5b76cafbf7d6060006270c90"),
"score" : 9,
"ranking" : NumberLong("3")
},
{
"_id" : ObjectId("5ba4fe6e71936b33e46569bb"),
"sgId" : ObjectId("5b7a4e69f7d606000566b65f"),
"score" : 8,
"ranking" : NumberLong("4")
},
{
"_id" : ObjectId("5ba4fe7471936b33e46569bc"),
"sgId" : ObjectId("5b7a4f47f7d6060006270cc4"),
"score" : 7,
"ranking" : NumberLong("5")
},
{
"_id" : ObjectId("5ba4fe8871936b33e46569bd"),
"sgId" : ObjectId("5b7a5265f7d606000566b67e"),
"score" : 6,
"ranking" : NumberLong("6")
}
]
Complete Query:
db.highscore.aggregate([
{
$sort: {score: -1}
},
{
$group: {
"_id": false,
"users": {
$push: {
"_id": "$_id",
"sgId": "$sgId",
"score": "$score",
}
}
}
},
{
$unwind: {
"path": "$users",
"includeArrayIndex": "ranking"
}
},
{
$group: {
"_id": false,
"users": {
$push: {
"_id": "$users._id",
"sgId": "$users.sgId",
"score": "$users.score",
"ranking": "$ranking"
}
}
}
},
{
$project: {
"users": "$users",
"myUser": {
$filter: {
"input": "$users",
"as": "user",
"cond": {
$eq: ["$$user.sgId", ObjectId("5b76c1000c3aa500060e0fd2")]
}
}
}
}
},
{
$project: {
"myUser": "$myUser",
"users" : {
$filter: {
"input": "$users",
"as": "users",
"cond": {
$and: [
{
$lte: [
"$$users.ranking",
{$add: ["$myUser[0].ranking", NumberLong("5")]}
]
},
{
$gte: [
"$$users.ranking",
{$subtract: ["$myUser[0].ranking", NumberLong("5")]}
]
}
]
}
}
}
}
},
])
Used Documents:
{
"_id" : ObjectId("5ba3c1d89a3a3e26a859f11a"),
"sgId" : ObjectId("5b76c1000c3aa500060e0fd2"),
"type" : "a",
"score" : 20,
"created" : ISODate("2018-09-20T17:50:48.024+02:00")
},
{
"_id" : ObjectId("5ba3c2089a3a3e26a859f11b"),
"sgId" : ObjectId("5b76c1040c3aa5000559e6b3"),
"type" : "a",
"score" : 30,
"created" : ISODate("2018-09-20T17:51:36.258+02:00")
},
{
"_id" : ObjectId("5ba4fa3b71936b33e46569b9"),
"sgId" : ObjectId("5b76c8a3f7d606000566b652"),
"type" : "a",
"score" : 10,
"created" : ISODate("2018-09-20T17:50:48.024+02:00")
},
{
"_id" : ObjectId("5ba4fa4c71936b33e46569ba"),
"sgId" : ObjectId("5b76cafbf7d6060006270c90"),
"type" : "a",
"score" : 9,
"created" : ISODate("2018-09-20T17:50:48.024+02:00")
}
Found it,
i just needed to add an $unwind before the last $project to convert the myUser Array into an object - then i was able to reach it for the add.
So full pipeline to get rankings of a highscore list and a range with your given user as source.
db.highscore.aggregate([
{
$sort: {score: -1}
},
{
$group: {
"_id": false,
"users": {
$push: {
"_id": "$_id",
"sgId": "$sgId",
"score": "$score",
}
}
}
},
{
$unwind: {
"path": "$users",
"includeArrayIndex": "ranking"
}
},
{
$group: {
"_id": false,
"users": {
$push: {
"_id": "$users._id",
"sgId": "$users.sgId",
"score": "$users.score",
"ranking": "$ranking"
}
}
}
},
{
$project: {
"users": "$users",
"myUser": {
$filter: {
"input": "$users",
"as": "user",
"cond": {
$eq: ["$$user.sgId", ObjectId("5b76c1000c3aa500060e0fd2")]
}
}
}
}
},
{
$unwind: {
path: '$myUser'
}
},
{
$project: {
"myUser": "$myUser",
"users" : {
$filter: {
"input": "$users",
"as": "users",
"cond": {
$and: [
{
$lte: [
"$$users.ranking",
{$add: ["$myUser.ranking", NumberLong("2")]}
]
},
{
$gte: [
"$$users.ranking",
{$subtract: ["$myUser.ranking", NumberLong("2")]}
]
}
]
}
}
}
}
},
], {'allowDiskUse': true})

MongoDB group and compute results from multiple fields within same document

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" }
}}
])

Compare 2 count aggregations

I have a collection in MongoDB that looks something like the following:
{ "_id" : 1, "type" : "start", userid: "101", placementid: 1 }
{ "_id" : 2, "type" : "start", userid: "101", placementid: 2 }
{ "_id" : 3, "type" : "start", userid: "101", placementid: 3 }
{ "_id" : 4, "type" : "end", userid: "101", placementid: 1 }
{ "_id" : 5, "type" : "end", userid: "101", placementid: 2 }
and I want to group results by userid then placementid and then count the types of "start" and "end", but only when the two counts are different. In this particular example I would want to get placementid: 3 because when grouped and counted this is the only case where the counts don't match.
I've written a query that gets the 2 counts and the grouping but I can't do the filtering when counts don't match. This is my query:
db.getCollection('mycollection').aggregate([
{
$project: {
userid: 1,
placementid: 1,
isStart: {
$cond: [ { $eq: ["$type", "start"] }, 1, 0]
},
isEnd: {
$cond: [ { $eq: ["$type", "end"] }, 1, 0]
}
}
},
{
$group: {
_id: { userid:"$userid", placementid:"$placementid" },
countStart:{ $sum: "$isStart" },
countEnd: { $sum: "$isEnd" }
}
},
{
$match: {
countStart: {$ne: "$countEnd"}
}
}
])
It seems like I'm using the match aggregation incorrectly because I'm seeing results where countStart and countEnd are the same.
{ "_id" : {"userid" : "101", "placementid" : "1"}, "countStart" : 1.0, "countEnd" : 1.0 }
{ "_id" : {"userid" : "101", "placementid" : "2"}, "countStart" : 1.0, "countEnd" : 1.0 }
{ "_id" : {"userid" : "101", "placementid" : "3"}, "countStart" : 1.0, "countEnd" : 0 }
Can anybody point into the right direction please?
To compare two fields inside $match stage you need $expr which is available in MongoDB 3.6:
db.myCollection.aggregate([
{
$project: {
userid: 1,
placementid: 1,
isStart: {
$cond: [ { $eq: ["$type", "start"] }, 1, 0]
},
isEnd: {
$cond: [ { $eq: ["$type", "end"] }, 1, 0]
}
}
},
{
$group: {
_id: { userid:"$userid", placementid:"$placementid" },
countStart:{ $sum: "$isStart" },
countEnd: { $sum: "$isEnd" }
}
},
{
$match: {
$expr: { $ne: [ "$countStart", "$countEnd" ] }
}
}
])
If you're using older version of MongoDB you can use $redact:
db.myCollection.aggregate([
{
$project: {
userid: 1,
placementid: 1,
isStart: {
$cond: [ { $eq: ["$type", "start"] }, 1, 0]
},
isEnd: {
$cond: [ { $eq: ["$type", "end"] }, 1, 0]
}
}
},
{
$group: {
_id: { userid:"$userid", placementid:"$placementid" },
countStart:{ $sum: "$isStart" },
countEnd: { $sum: "$isEnd" }
}
},
{
$redact: {
$cond: { if: { $ne: [ "$countStart", "$countEnd" ] }, then: "$$KEEP", else: "$$PRUNE" }
}
}
])
You run do the following pipeline to get this - no need to use $expr or $redact or anything special really:
db.mycollection.aggregate({
$group: {
_id: {
"userid": "$userid",
"placementid": "$placementid"
},
"sum": {
$sum: {
$cond: {
if: { $eq: [ "$type", "start" ] },
then: 1, // +1 for start
else: -1 // -1 for anything else
}
}
}
}
}, {
$match: {
"sum": { $ne: 0 } // only return the non matching-up ones
}
})

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
]
}
}
}
}
])

Aggregate query in MongoDB

I'm trying to create some daily stats from a MongoDB table. The document contains messages that have a create-date, state (Warn, Error, Complete). I'd like to product a query that results in one record per - Date,Count of Warn, Count of Error, Count of Complete. I'm a newbie with Mongo and just learning the query language. I've tried aggregation with mixed results:
db.TransactionLogs.aggregate(
{ $group : {
_id : {
category: {$substr:["$startDate",0,10]},
term: "$Status",
},
total: { $sum : 2 }
}
})
results in multiple records per date by status:
"result" : [
{
"_id" : {
"category" : "2015-02-10",
"term" : "Completed",
},
"total" : 532
},
{
"_id" : {
"category" : "2015-02-10",
"term" : "Error",
},
"total" : 616
},
Message:
{ "_id" : "2ceda481-3dd3-480d-800d-95288edce6f2", "MID" : "02de5194-7a1d-4854-922c-934902840136", "Status" : "Completed", "firstName" : "Willy", "lastName" : "Wire", "allocation" : "100", "initEvent" : "Marriage", "system" : "Oracle", "startDate" : "2015-02-06T19:03:34.237Z", "stopDate" : "2015-02-06T19:23:34.237Z", "plan" : "445-A" }
I'm sure that its a lack of understanding of aggregation on my part. Any help or direction is greatly appreciated!
I figured it out. I needed to look at how to "pivot" in Mongo. This works:
db.TransactionLogs.aggregate([ { $project: { startdate: {$substr:["$startDate",0,10]},
cnt_e1: { $cond: [ { $eq: [ "$Status", "Error" ] }, "$count", 1 ] },
cnt_e2: { $cond: [ { $eq: [ "$Status", "Warning" ] }, "$count", 1 ] },
cnt_e3: { $cond: [ { $eq: [ "$Status", "Completed" ] }, "$count", 1 ] },
} },
{ $group: { _id: "$startdate", cnt_e1: { $sum: "$cnt_e1" }, cnt_e2: { $sum: "$cnt_e2" }, cnt_e3: { $sum: "$cnt_e3" } } },
{ $sort: { _id: 1 } },
Here's the code...
db.TransactionLogs.aggregate([ { $project: { startdate: {$substr:["$startDate",0,10]},
cnt_e1: { $cond: [ { $eq: [ "$Status", "Error" ] }, "$count", 1 ] },
cnt_e2: { $cond: [ { $eq: [ "$Status", "Warning" ] }, "$count", 1 ] },
cnt_e3: { $cond: [ { $eq: [ "$Status", "Completed" ] }, "$count", 1 ] },
} },
{ $group: { _id: "$startdate", cnt_e1: { $sum: "$cnt_e1" }, cnt_e2: { $sum: "$cnt_e2" }, cnt_e3: { $sum: "$cnt_e3" } } },
{ $sort: { _id: 1 } },