How to merge/join mongodb aggregate? - mongodb

Given this dataset:
db.calls.insert([{
"agent": 2,
"isFromOutside": true,
"duration": 304
}, {
"agent": 1,
"isFromOutside": false,
"duration": 811
}, {
"agent": 0,
"isFromOutside": true,
"duration": 753
}, {
"agent": 1,
"isFromOutside": false,
"duration": 593
}, {
"agent": 3,
"isFromOutside": true,
"duration": 263
}, {
"agent": 0,
"isFromOutside": true,
"duration": 995
}, {
"agent": 0,
"isFromOutside": false,
"duration": 210
}, {
"agent": 1,
"isFromOutside": false,
"duration": 737
}, {
"agent": 2,
"isFromOutside": false,
"duration": 170
}, {
"agent": 0,
"isFromOutside": false,
"duration": 487
}])
I have two aggregate queries that give the total duration for each agent and the count of outgoing calls for each client:
get outGoingCalls table:
db.calls.aggregate([
{ $match: { duration :{ $gt: 0 }, isFromOutside: false } },
{ $group: { _id: "$agent", outGoingCalls: { $sum: 1 } } },
{ $sort: { outGoingCalls: -1 } }
])
get totalDuration table:
db.calls.aggregate([
{ $group: { _id: "$agent", totalDuration: { $sum: "$duration" } } },
{ $sort: {totalDuration: -1 } }
])
How to merge/join these tables (or do only one aggregation) to have something like this:
[
{_id: 0, totalDuration: ..., outGoingCalls: ...},
{_id: 1, totalDuration: ..., outGoingCalls: ...},
{_id: 2, totalDuration: ..., outGoingCalls: ...},
...
]

Try the following aggregation framework:
db.calls.aggregate([
{
"$group": {
"_id": "$agent",
"outGoingCalls": {
"$sum": {
"$cond": [
{
"$and": [
{"$gt": ["$duration", 0 ]},
{"$eq": ["$isFromOutside", false ]}
]
},
1,
0
]
}
},
"totalDuration": { "$sum": "$duration" }
}
},
{
"$sort": {
"totalDuration": -1,
"outGoingCalls": -1
}
}
])
Output:
/* 0 */
{
"result" : [
{
"_id" : 0,
"outGoingCalls" : 2,
"totalDuration" : 2445
},
{
"_id" : 1,
"outGoingCalls" : 3,
"totalDuration" : 2141
},
{
"_id" : 2,
"outGoingCalls" : 1,
"totalDuration" : 474
},
{
"_id" : 3,
"outGoingCalls" : 0,
"totalDuration" : 263
}
],
"ok" : 1
}

Related

Sort multiple levels of array after group in Mongo Java

I have documents with below schema
id :
currencyCode : "USD"
businessDayStartDate : ""
hourZoneNumber : 1
customerCount : 0
itemQuantity : 4
nodeId : "STORE_DEV"
endpointId : "998"
amount : 4
I am trying to find documents that match nodeId and trying to aggregate customerCount, itemQuantity and amount for each hourZoneNumber.
Below is the query
db.getCollection("xxx").aggregate([
{ "$match": { "nodeId": { "$in":["STORE_DEV_1","STORE_DEV_2"] }, "businessDayStartDate" : { "$gte": "2022-03-04" , "$lte": "2022-03-07" } }},
{ "$group": {
"_id": {
"nodeId": "$nodeId",
"endpointId": "$endpointId",
"hourZoneNumber": "$hourZoneNumber"
},
"customerCount": { "$sum": "$customerCount" },
"itemQuantity" : { "$sum": "$itemQuantity" },
"amount" : { "$sum": "$amount" }
}
},
{ "$group": {
"_id": {
"nodeId": "$_id.nodeId",
"endpointId": "$_id.endpointId"
},
"hourZones": {
"$addToSet": {
"hourZoneNumber": "$_id.hourZoneNumber",
"customerCount": { "$sum": "$customerCount" },
"itemQuantity" : { "$sum": "$itemQuantity" },
"amount" : { "$sum": "$amount" }
}
}
}
},
{ "$group": {
"_id": "$_id.nodeId",
"endpoints": {
"$addToSet": {
"endpointId": "$_id.endpointId",
"hourZones": "$hourZones"
}
},
"total": {
"$addToSet": {
"customerCount": { "$sum": "$hourZones.customerCount" },
"itemQuantity" : { "$sum": "$hourZones.itemQuantity" },
"amount" : { "$sum": "$hourZones.amount" }
}
}
}
},
{
$project: {
_id: 0,
nodeId: "$_id",
endpoints: 1,
hourZones: 1,
total: 1
}
}
])
Output is as below:
{
nodeId: 'STORE_DEV_2',
endpoints: [
{ endpointId: '998',
hourZones:
[
{ hourZoneNumber: 1,
customerCount: 0,
itemQuantity: 4,
amount: Decimal128("4") }
] } ],
total: [ { customerCount: 0, itemQuantity: 4, amount: Decimal128("4") } ],
}
{
nodeId: 'STORE_DEV_1',
endpoints:
[ { endpointId: '999',
hourZones:
[ { hourZoneNumber: 2,
customerCount: 2,
itemQuantity: 4,
amount: Decimal128("4") },
{ hourZoneNumber: 1,
customerCount: 4,
itemQuantity: 8,
amount: Decimal128("247.56") } ] } ],
total:
[ { customerCount: 6,
itemQuantity: 12,
amount: Decimal128("251.56") } ]
}
I want the output to be sorted as : First sort by nodeId, then by endpointId within the endpoints and lastly by hourZoneNumber within hourZones.
How do I do this ? I tried using sort() with all the three fields. But it did not work. Also, can someone please confirm if there is any better way than the above code, as I am new to Mongo DB.
Edit:
Please find sample input data at https://mongoplayground.net/p/FYm3QMMgrNI
Since you already have the separated data at the beginning, it is simply a matter of saving these values through the grouping and then sorting by them in the end.
Edit: In order to sort each inner array, we use $push instead of $addToSet inside the $group and $sort before each $group:
db.collection.aggregate([
{
"$match": {
"nodeId": {"$in": ["STORE_DEV_TTEC", "STORE_DEV_TTEZ"]
},
"businessDayStartDate": {"$gte": "2022-03-04", "$lte": "2022-03-07"}
}
},
{
"$sort": {"nodeId": 1, "endpointId": 1, "hourZoneNumber": 1}
},
{
"$group": {
"_id": {
"nodeId": "$nodeId",
"endpointId": "$endpointId",
"hourZoneNumber": "$hourZoneNumber"
},
"customerCount": {"$sum": "$customerCount"},
"itemQuantity": {"$sum": "$itemQuantity"},
"amount": {"$sum": "$amount"}
}
},
{"$sort": {"_id.hourZoneNumber": 1}
},
{
"$group": {
"_id": {
"nodeId": "$_id.nodeId",
"endpointId": "$_id.endpointId"
},
"hourZones": {
"$push": {
"hourZoneNumber": "$_id.hourZoneNumber",
"customerCount": {"$sum": "$customerCount"},
"itemQuantity": {"$sum": "$itemQuantity"},
"amount": {"$sum": "$amount"}
}
},
hourZoneKey: {$first: "$_id.hourZoneNumber"}
}
},
{"$sort": {"_id.endpointId": 1}
},
{
"$group": {
"_id": "$_id.nodeId",
"endpoints": {
"$push": {
"endpointId": "$_id.endpointId",
"hourZones": "$hourZones"
}
},
endpointKey: {$first: "$_id.endpointId"},
hourZoneKey: {$first: "$hourZoneKey"}
}
},
{"$sort": {"nodeId": 1, "endpointKey": 1, "hourZoneKey": 1}
},
{
$project: {_id: 0, nodeId: "$_id", endpoints: 1, hourZones: 1, total: 1}
}
])
You can see it here

Aggregation for computing distribution across array

I'm trying to create an aggregation that will compute the distribution of values across an array of objects and return an array of computed values.
Here is a sample document
[
{
"duration": 1208,
"dataPoints": 2,
"binMin": 0,
"binMax": 5000
},
{
"duration": 25735,
"dataPoints": 3,
"binMin": 5000,
"binMax": 10000
},
{
"duration": 0,
"dataPoints": 0,
"binMin": 10000,
"binMax": 20000
},
{
"duration": 54088,
"dataPoints": 2,
"binMin": 20000,
"binMax": 28817
}
]
I need to add up the durations for each object, then compute the distribution across each object and return a new array like so:
[
{
"duration": 1208,
"dataPoints": 2,
"binMin": 0,
"binMax": 5000,
"ratio": 0.014907874763979
},
{
"duration": 25735,
"dataPoints": 3,
"binMin": 5000,
"binMax": 10000,
"ratio": 0.317594500870037
},
{
"duration": 0,
"dataPoints": 0,
"binMin": 10000,
"binMax": 20000,
"ratio": 0
},
{
"duration": 54088,
"dataPoints": 2,
"binMin": 20000,
"binMax": 28817,
"ratio": 0.667497624365983
}
]
I am able to calculate the total duration and divide to get the ratio value but it seems to be only doing it to the first element of the array.
This is my aggregation so far:
[{$project: {
_id: '$_id',
username: 1,
uuid: 1,
data: '$stats.dataHistogram'
}}, {$unwind: {
path: '$data'
}}, {$group: {
_id: '$_id',
data_bin: {
$first: '$data'
},
total_duration: {
$sum: '$data.duration'
}
}}, {$project: {
_id: '$_id',
total_duration: 1,
data_bin: 1,
ratio: {
$divide: [
'$data_bin.duration',
{
$add: [
'$total_duration',
1
]
}
]
}
}}]
(I'm adding a 1 to the $total_duration because it can be 0 some times and I get a "Cannot divide by zero" error)
I feel like I'm super close but not sure what the next steps should be. Thanks for the help!
You can use $reduce to compute the total duration first. Then apply element wise $divide by using $map
db.collection.aggregate([
{
"$addFields": {
"totalDuration": {
"$reduce": {
"input": "$stats.histogram",
"initialValue": 0,
"in": {
$add: [
"$$value",
"$$this.duration"
]
}
}
}
}
},
{
"$addFields": {
"totalDuration": {
"$cond": {
"if": {
$eq: [
"$totalDuration",
0
]
},
"then": 1,
"else": "$totalDuration"
}
}
}
},
{
"$addFields": {
"stats.histogram": {
"$map": {
"input": "$stats.histogram",
"as": "h",
"in": {
"duration": "$$h.duration",
"dataPoints": "$$h.dataPoints",
"binMin": "$$h.binMin",
"binMax": "$$h.binMax",
"ratio": {
"$divide": [
"$$h.duration",
"$totalDuration"
]
}
}
}
}
}
}
])
Here is the Mongo playground for your reference.

Get Highest Value By Hour in MongoDB for given Date Range?

I have the following document structure in MongoDB :
{
"_id" : ObjectId("5c1b7451b1829b69963029ea"),
"duration" : 92,
"accountId" : ObjectId("9aafe7b01cf4560c9bb5d68"),
"createdAt" : ISODate("2018-12-20T10:52:01.560Z"),
"__v" : 0,
},
{
"_id" : ObjectId("5c1b7451b1829b69963029ea"),
"duration" : 192,
"accountId" : ObjectId("9aafe7b01cf4560c9bb5d68"),
"createdAt" : ISODate("2018-12-20T11:52:01.560Z"),
"__v" : 0,
}
Now I want to get the highest sum of duration for the day with corresponding hour. Technically, something like this :
{
"readableDate" : "2018-12-20",
"hour" : 11,
"total" : 192
}
Where total is the hourly total which is HIGHEST for that particular day.
The query which I have tried is as follows :
db.getCollection('operational_details').aggregate(
{"$match": {"accountId": ObjectId("9aafe7b01cf4560c9bb5d68"),
"createdAt": {"$gte": ISODate("2019-06-01T10:30:29.725Z"),
"$lte": ISODate("2019-06-04T10:30:29.725Z")},
}},
{ "$project": {
"date": {"$dateToString": {"format": "%Y-%m-%d", "date": "$createdAt"}},
"hour": {"$hour":"$createdAt"},
"total":{"$sum": "$duration"} }
},
{ "$group":{
"_id": { "hour":"$hour","date":"$date"},
"max": {"$max": "$total"}
}})
Hope I am clear with my example. TIA
Please try the below
working playground link
//Array
[
{
"_id": ObjectId("5cf4f20243f560e1e0a77014"),
"duration": 92,
"accountId": ObjectId("6ef4f20243f560e1e0a77015"),
"createdAt": ISODate("2018-12-20T10:52:10.320Z")
},
{
"_id": ObjectId("5cf4f21843f560e1e0a7701a"),
"duration": 192,
"accountId": ObjectId("6ef4f20243f560e1e0a77015"),
"createdAt": ISODate("2018-12-20T11:52:11.123Z")
}
]
//Script
db.collection.aggregate([
{
"$match": {
"accountId": {
$eq: ObjectId("6ef4f20243f560e1e0a77015")
},
"createdAt": {
$gte: ISODate("2018-12-19T10:30:00.000Z"),
$lte: ISODate("2018-12-21T10:30:00.000Z")
}
}
},
{
"$project": {
"date": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$createdAt"
}
},
"hour": {
"$hour": "$createdAt"
},
"duration": "$duration"
}
},
{
"$group": {
"_id": {
"hour": "$hour",
"date": "$date"
},
"total": {
"$sum": "$duration"
}
}
},
{
"$project": {
"readableDate": "$_id.date",
"hour": "$_id.hour",
"total": "$total"
}
},
{
"$project": {
"_id": 0
}
},
{
"$sort": {
"total": -1
}
},
{
"$limit": 1
}
])
//Result
[
{
"hour": 11,
"readableDate": "2018-12-20",
"total": 192
}
]

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

MongoDB avoid duplicates using $addToSet in aggregation pipeline

there is aggregation pipeline:
db.getCollection('yourCollection').aggregate(
{
$unwind: {
path: "$dates",
includeArrayIndex: "idx"
}
},
{
$project: {
_id: 0,
dates: 1,
numbers: { $arrayElemAt: ["$numbers", "$idx"] },
goals: { $arrayElemAt: ["$goals", "$idx"] },
durations: { $arrayElemAt: ["$durations", "$idx"] }
}
}
)
which perform on the following data (sample documents):
{
"_id" : ObjectId("52d017d4b60fb046cdaf4851"),
"dates" : [
1399518702000,
1399126333000,
1399209192000,
1399027545000
],
"dress_number" : "4",
"name" : "J. Evans",
"numbers" : [
"5982",
"5983",
"5984",
"5985"
],
"goals": [
"1",
"0",
"4",
"2"
],
"durations": [
"78",
"45",
"90",
"90"
]
}
{
"_id" : ObjectId("57e250c1b60fb0213d06737c"),
"dates" : [
"1399027545000",
"1399101432000",
"1399026850000",
"1399904504000"
],
"dress_number" : "6",
"name" : K. Mitnick,
"numbers" : [
"0982",
"0981",
"0958",
"0982"
],
"durations" : [
98,
110,
66,
92
],
"goals" : [
"2",
"3",
"0",
"1"
]
}
The query works good, but there are duplicate records so I'm trying to use $addToSet operator to avoid duplicates:
db.getCollection('yourCollection').aggregate(
{
$match: {
"number": number
}
},
{
$unwind: {
path: "$dates",
includeArrayIndex: "idx"
}
},
$group: {
_id: '$_id',
dates: { $addToSet: '$dates' }
},
{
$project: {
_id: 0,
dates: 1,
numbers: { $arrayElemAt: ["$numbers", "$idx"] },
goals: { $arrayElemAt: ["$goals", "$idx"] },
durations: { $arrayElemAt: ["$durations", "$idx"] }
}
}
)
but I got only dates (other field are null)
{ dates:
[ '1399026850000',
'1399101432000',
'1399027545000',
'1399904504000',
'1399024474000',
'1399126333000' ],
numbers: null,
goals: null,
durations: null },
{ dates:
[ '1399027545000',
'1399024474000',
'1399518702000',
'1399126333000',
'1399209192000',
'1399356651000' ],
numbers: null,
goals: null,
conversation_durations: null },
{ dates:
[ '1399026850000',
'1399101432000',
'1399027545000',
'1399904504000',
'1399024474000' ],
numbers: null,
goals: null,
durations: null }
Does anybody know where is the problem?
You need to include the fields within the $group pipeline using the $first operator as follows:
db.getCollection('yourCollection').aggregate([
{ "$unwind": "$dates" },
{
"$group": {
"_id": "$_id",
"dates": { "$addToSet": "$dates" },
"numbers": { "$first": "$numbers" },
"goals": { "$first": "$goals" },
"durations": { "$first": "$durations" }
}
},
{ "$unwind": {
"path": "$dates",
"includeArrayIndex": "idx"
} },
{
"$project": {
"_id": 0,
"dates": 1,
"numbers": { "$arrayElemAt": ["$numbers", "$idx"] },
"goals": { "$arrayElemAt": ["$goals", "$idx"] },
"durations": { "$arrayElemAt": ["$durations", "$idx"] }
}
}
])
or using $setUnion to eliminate duplicates as:
db.getCollection('yourCollection').aggregate([
{
"$project": {
"_id": 0,
"dates": { "$setUnion": ["$dates", "$dates"] },
"numbers": 1,
"goals": 1,
"durations": 1
}
}
{ "$unwind": {
"path": "$dates",
"includeArrayIndex": "idx"
} },
{
"$project": {
"_id": 0,
"dates": 1,
"dateIndex": "$idx",
"numbers": { "$arrayElemAt": ["$numbers", "$idx"] },
"goals": { "$arrayElemAt": ["$goals", "$idx"] },
"durations": { "$arrayElemAt": ["$durations", "$idx"] }
}
}
])