I know these have been asked a bunch and I am brand new to MongoDB which means I am struggling. I am using compass and trying to figure out this aggregation pipeline. In short, I need to get the average time difference between the max and min timestamp grouped by id.
The expected result would just be: avg_time: 234.00 or such.
The equivalent MySQL query looks like this:
select SEC_TO_TIME(AVG(TIME_TO_SEC(TIMEDIFF(a.maxDate,a.minDate)))) FROM (select id, min(timestamp) as minDate, max(timestamp) as maxDate from counterHistory group by id) as a
Here is what the dataset looks like:
[{
"_id": {
"$oid": "617dce992743dd52bed811a6"
},
"dateStart": {
"$date": "2021-10-30T23:00:41.056Z"
},
"dateEnd": {
"$date": "2021-10-30T23:00:52.404Z"
},
"areas": {
"c2acc5cc-9a7a-4406-8d91-79cb7f7ded70": {
"color": "yellow",
"type": "rightleft_bottomtop",
"location": {
"point1": {
"x": 1397,
"y": 702
},
"point2": {
"x": 1808,
"y": 645
},
"refResolution": {
"w": 1920,
"h": 969
}
},
"computed": {
"a": 0.15457277801631616,
"b": -332.7843438566361,
"lineBearings": [
81.21317228796154,
261.2131722879615
],
"point1": {
"x": 465.6666666666667,
"y": -260.80495356037153
},
"point2": {
"x": 602.6666666666666,
"y": -239.62848297213623
}
},
"name": "Right line start"
},
"56885eaf-9808-4b5e-b193-06b20e10c39d": {
"color": "turquoise",
"type": "rightleft_bottomtop",
"location": {
"point1": {
"x": 770,
"y": 411
},
"point2": {
"x": 1085,
"y": 360
},
"refResolution": {
"w": 1920,
"h": 969
}
},
"computed": {
"a": 0.18045112781954886,
"b": -199.0092879256966,
"lineBearings": [
79.77099171264048,
259.77099171264047
],
"point1": {
"x": 256.6666666666667,
"y": -152.6934984520124
},
"point2": {
"x": 361.6666666666667,
"y": -133.74613003095976
}
},
"name": "right lane end"
}
},
"videoResolution": {
"w": 640,
"h": 360
},
"filename": "demo.mp4",
"counterSummary": {
"56885eaf-9808-4b5e-b193-06b20e10c39d": {
"_total": 8,
"car": 8
},
"c2acc5cc-9a7a-4406-8d91-79cb7f7ded70": {
"_total": 8,
"car": 7,
"truck": 1
}
},
"trackerSummary": {
"totalItemsTracked": 64
},
"counterHistory": [
{
"frameId": 29,
"timestamp": {
"$date": "2021-10-30T23:00:42.694Z"
},
"area": "c2acc5cc-9a7a-4406-8d91-79cb7f7ded70",
"name": "car",
"id": 408,
"bearing": 291.8014094863518,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 30.588237198390278
},
{
"frameId": 43,
"timestamp": {
"$date": "2021-10-30T23:00:43.619Z"
},
"area": "c2acc5cc-9a7a-4406-8d91-79cb7f7ded70",
"name": "truck",
"id": 457,
"bearing": 293.1985905136482,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 31.985418225686644
},
{
"frameId": 50,
"timestamp": {
"$date": "2021-10-30T23:00:44.063Z"
},
"area": "56885eaf-9808-4b5e-b193-06b20e10c39d",
"name": "car",
"id": 421,
"bearing": 303.69006752597977,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 43.919075813339305
},
{
"frameId": 63,
"timestamp": {
"$date": "2021-10-30T23:00:44.927Z"
},
"area": "c2acc5cc-9a7a-4406-8d91-79cb7f7ded70",
"name": "car",
"id": 458,
"bearing": 293.6293777306568,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 32.41620544269528
},
{
"frameId": 65,
"timestamp": {
"$date": "2021-10-30T23:00:45.054Z"
},
"area": "56885eaf-9808-4b5e-b193-06b20e10c39d",
"name": "car",
"id": 464,
"bearing": 284.03624346792645,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 24.265251755286005
},
{
"frameId": 78,
"timestamp": {
"$date": "2021-10-30T23:00:45.888Z"
},
"area": "c2acc5cc-9a7a-4406-8d91-79cb7f7ded70",
"name": "car",
"id": 469,
"bearing": 303.69006752597977,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 42.47689523801825
},
{
"frameId": 86,
"timestamp": {
"$date": "2021-10-30T23:00:46.415Z"
},
"area": "56885eaf-9808-4b5e-b193-06b20e10c39d",
"name": "car",
"id": 427,
"bearing": 354.28940686250036,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 85.48158485014012
},
{
"frameId": 122,
"timestamp": {
"$date": "2021-10-30T23:00:48.757Z"
},
"area": "c2acc5cc-9a7a-4406-8d91-79cb7f7ded70",
"name": "car",
"id": 479,
"bearing": 296.565051177078,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 35.35187888911645
},
{
"frameId": 125,
"timestamp": {
"$date": "2021-10-30T23:00:48.946Z"
},
"area": "56885eaf-9808-4b5e-b193-06b20e10c39d",
"name": "car",
"id": 408,
"bearing": 323.13010235415595,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 63.359110641515514
},
{
"frameId": 143,
"timestamp": {
"$date": "2021-10-30T23:00:50.143Z"
},
"area": "56885eaf-9808-4b5e-b193-06b20e10c39d",
"name": "car",
"id": 473,
"bearing": 284.03624346792645,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 24.265251755286005
},
{
"frameId": 152,
"timestamp": {
"$date": "2021-10-30T23:00:50.716Z"
},
"area": "c2acc5cc-9a7a-4406-8d91-79cb7f7ded70",
"name": "car",
"id": 438,
"bearing": 296.565051177078,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 35.35187888911645
},
{
"frameId": 160,
"timestamp": {
"$date": "2021-10-30T23:00:51.242Z"
},
"area": "56885eaf-9808-4b5e-b193-06b20e10c39d",
"name": "car",
"id": 455,
"bearing": 45,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 34.77099171264047
},
{
"frameId": 174,
"timestamp": {
"$date": "2021-10-30T23:00:52.149Z"
},
"area": "c2acc5cc-9a7a-4406-8d91-79cb7f7ded70",
"name": "car",
"id": 492,
"bearing": 327.2647737278924,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 66.05160143993088
},
{
"frameId": 175,
"timestamp": {
"$date": "2021-10-30T23:00:52.212Z"
},
"area": "56885eaf-9808-4b5e-b193-06b20e10c39d",
"name": "car",
"id": 469,
"bearing": 281.30993247402023,
"countingDirection": "rightleft_bottomtop",
"angleWithCountingLine": 21.538940761379738
}
]
}]
Here is my atrocious pipeline that at least gives me the result that I am looking for. So I guess, how do you optimize this?
[{$match: {
_id:ObjectId('617dce992743dd52bed811a6')
}}, {$unwind: {
path: "$counterHistory",
}}, {$group: {
_id: "$counterHistory.id",
maxDate:{$max:"$counterHistory.timestamp"},
minDate:{$min:"$counterHistory.timestamp"}
}}, {$project: {
_id:1,
minDate:1,
maxDate:1,
noMatchingDates:{$ne:["$maxDate","$minDate"]}
}}, {$match: {
noMatchingDates:true
}}, {$group: {
_id: null,
"avg_time": {
"$avg": {
"$subtract": [
{ "$ifNull": [ "$maxDate", 0 ] },
{ "$ifNull": [ "$minDate", 0 ] }
]
}
}
}}, {$project: {
avg_time:1,
hours: { $divide: [ "$avg_time", 3600000 ] },
minutes: { $divide: [ "$avg_time", 60000 ] },
seconds: { $divide: [ "$avg_time", 1000 ] }
}}]
So as I put up above and confirmed by YuTing, this pipeline works:
[{$match: {
_id:ObjectId('617dce992743dd52bed811a6')
}}, {$unwind: {
path: "$counterHistory",
}}, {$group: {
_id: "$counterHistory.id",
maxDate:{$max:"$counterHistory.timestamp"},
minDate:{$min:"$counterHistory.timestamp"}
}}, {$project: {
_id:1,
minDate:1,
maxDate:1,
noMatchingDates:{$ne:["$maxDate","$minDate"]}
}}, {$match: {
noMatchingDates:true
}}, {$group: {
_id: null,
"avg_time": {
"$avg": {
"$subtract": [
{ "$ifNull": [ "$maxDate", 0 ] },
{ "$ifNull": [ "$minDate", 0 ] }
]
}
}
}}, {$project: {
avg_time:1,
hours: { $divide: [ "$avg_time", 3600000 ] },
minutes: { $divide: [ "$avg_time", 60000 ] },
seconds: { $divide: [ "$avg_time", 1000 ] }
}}]
Related
I have a mongodb document for customer streaming activations.
[
{
"_id": 1,
"email": "customer1#email.com",
"packageid": "movies",
"command": "activated",
"tid": "123",
"createdAt": ISODate("2021-06-08")
},
{
"_id": 2,
"email": "customer2#email.com",
"packageid": "movies",
"command": "activated",
"tid": "124",
"createdAt": ISODate("2021-06-20")
},
{
"_id": 3,
"email": "customer1#email.com",
"packageid": "movies",
"command": "deactivated",
"tid": "1234",
"createdAt": ISODate("2021-06-10")
},
{
"_id": 4,
"email": "customer2#email.com",
"packageid": "movies",
"command": "deactivated",
"tid": "1244",
"createdAt": ISODate("2021-06-22")
},
{
"_id": 5,
"email": "customer1#email.com",
"packageid": "movies",
"command": "activated",
"tid": "123",
"createdAt": ISODate("2021-06-11")
},
{
"_id": 6,
"email": "customer2#email.com",
"packageid": "movies",
"command": "activated",
"tid": "1244",
"createdAt": ISODate("2021-06-23")
},
{
"_id": 7,
"email": "customer1#email.com",
"packageid": "movies",
"command": "deactivated",
"tid": "1237",
"createdAt": ISODate("2021-06-15")
},
{
"_id": 8,
"email": "customer2#email.com",
"packageid": "movies",
"command": "deactivated",
"tid": "1244",
"createdAt": ISODate("2021-06-25")
},
]
now I wanna group by email and get each customer activated days for specific time frame. let's say 1 month. I've been trying this for few hours
{
"email":"customer1#email.com"
"packageid":"movies",
"days": 3
},
{
"email":"customer1#email.com"
"packageid":"movies",
"days": 5
},
{
"email":"customer2#email.com"
"packageid":"movies",
"days": 3
},
{
"email":"customer2#email.com"
"packageid":"movies",
"days": 3
}
edit: any user can activate then deactivate the service any time they want sometimes users do activate and deactivate multiple times within a same month.
I want to find out how many days customer was activated.
We can use $setWindowFields to compute the $dateDiff and $group the sum.
db.collection.aggregate([
{
"$setWindowFields": {
"partitionBy": {
email: "$email",
packageid: "$packageid"
},
"sortBy": {
"createdAt": 1
},
"output": {
"next": {
$shift: {
output: "$createdAt",
by: 1
}
}
}
}
},
{
$match: {
"command": "activated"
}
},
{
$project: {
email: "$email",
packageid: "$packageid",
"days": {
"$dateDiff": {
startDate: "$createdAt",
endDate: {
$ifNull: [
"$next",
"$$NOW"
]
},
unit: "day"
}
}
}
}
])
Here is the Mongo Playground for your reference.
I have this collection:
[
{
"_id": {
"$oid": "60b22e1dbd46fa18a8308318"
},
"title": "basketball",
"price": 12,
"category": "Furniture",
"description": "",
"images": [
"http://res.cloudinary.com/hadarush100/image/upload/v1622289949/nfg948x3zro6gbiuknrz.jpg"
],
"categoryId": 1,
"userId": "60ad16493062eb11141d4927",
"createdAt": 1622289948232,
"chats": [
{
"id": 1,
"createdAt": 1622289948232,
"messages": [
{
"id": "1",
"createdAt": 1622289948232,
"senderId": "60ad16493062eb11141d4927",
"text": "Hello, Im the seller of this product."
}
]
},
{
"id": "2",
"createdAt": 1622289948232,
"messages": [
{
"id": 1,
"createdAt": 1622289948232,
"senderId": "60ad16493062eb11141d4927",
"text": "Hello, Im the seller of this product."
}
]
}
]
}
]
and i want to find specific document (by _id), then dive into specific chat in this document (by id), than use $lookup for replacing the "senderId" property in each message with a "sender" property that contains the full sender details (as a user), that exist in another collection (users). the result needs to look like this:
[
{
"_id": {
"$oid": "60b22e1dbd46fa18a8308318"
},
"title": "basketball",
"price": 12,
"category": "Furniture",
"description": "",
"images": [
"http://res.cloudinary.com/hadarush100/image/upload/v1622289949/nfg948x3zro6gbiuknrz.jpg"
],
"categoryId": 1,
"userId": "60ad16493062eb11141d4927",
"createdAt": 1622289948232,
"chats": [
{
"id": 1,
"createdAt": 1622289948232,
"messages": [
{
"id": "1",
"createdAt": 1622289948232,
"sender": {
"_id": {
"$oid": "60ad16493062eb11141d4927"
},
"username": "hadar",
"email": "hadarushha#gmail.com",
"profileImgUrl": "https://randomuser.me/api/portraits/men/79.jpg",
"createdAt": 1621956168518
},
"text": "Hello, Im the seller of this product."
}
]
},
{
"id": "2",
"createdAt": 1622289948232,
"messages": [
{
"id": 1,
"createdAt": 1622289948232,
"sender": {
"_id": {
"$oid": "60ad16493062eb11141d4927"
},
"username": "hadar",
"email": "hadarushha#gmail.com",
"profileImgUrl": "https://randomuser.me/api/portraits/men/79.jpg",
"createdAt": 1621956168518
},
"text": "Hello, Im the seller of this product."
}
]
}
]
}
]
You can use this aggregation:
$match to filter only selected document (_id)
$unwind multiple time to transform arrays into objects
$lookup to query external collection (users)
$group in reverse order
I assumed that your collections are more or less like this (next time, post both collections and also an example on a working playground)
db={
"products": [
{
"_id": {
"$oid": "60b22e1dbd46fa18a8308318"
},
"title": "basketball",
"price": 12,
"category": "Furniture",
"description": "",
"images": [
"http://res.cloudinary.com/hadarush100/image/upload/v1622289949/nfg948x3zro6gbiuknrz.jpg"
],
"categoryId": 1,
"userId": "60ad16493062eb11141d4927",
"createdAt": 1622289948232,
"chats": [
{
"id": 1,
"createdAt": 1622289948232,
"messages": [
{
"id": "1",
"createdAt": 1622289948232,
"senderId": "60ad16493062eb11141d4927",
"text": "Hello, Im the seller of this product."
}
]
},
{
"id": "2",
"createdAt": 1622289948232,
"messages": [
{
"id": 1,
"createdAt": 1622289948232,
"senderId": "60ad16493062eb11141d4927",
"text": "Hello, Im the seller of this product."
}
]
}
]
},
{
"_id": {
"$oid": "60b22e1dbd46fa18a8308319"
},
"title": "volleyball",
"price": 8,
"category": "Furniture",
"description": "",
"images": [
"http://res.cloudinary.com/hadarush100/image/upload/v1622289949/nfg948x3zro6gbiuknrz.jpg"
],
"categoryId": 1,
"userId": "60ad16493062eb11141d4927",
"createdAt": 1622289948232,
"chats": [
{
"id": 1,
"createdAt": 1622289948232,
"messages": [
{
"id": "1",
"createdAt": 1622289948232,
"senderId": "60ad16493062eb11141d4927",
"text": "Hello, Im the seller of this product."
}
]
},
{
"id": "2",
"createdAt": 1622289948232,
"messages": [
{
"id": 1,
"createdAt": 1622289948232,
"senderId": "60ad16493062eb11141d4928",
"text": "Hello, Im the seller of this product."
}
]
}
]
}
],
"users": [
{
"_id": {
"$oid": "60ad16493062eb11141d4927"
},
"username": "hadar",
"email": "hadarushha#gmail.com",
"profileImgUrl": "https://randomuser.me/api/portraits/men/79.jpg",
"createdAt": 1621956168518
},
{
"_id": {
"$oid": "60ad16493062eb11141d4928"
},
"username": "test",
"email": "test#gmail.com",
"profileImgUrl": "https://randomuser.me/api/portraits/men/49.jpg",
"createdAt": 1621956168528
},
]
}
And here is the working aggregation:
db.products.aggregate([
{
"$match": {
"_id": {
"$oid": "60b22e1dbd46fa18a8308319"
}
}
},
{
"$unwind": "$chats"
},
{
"$unwind": "$chats.messages"
},
{
"$addFields": {
"chats.messages.senderIdObjId": {
"$convert": {
"input": "$chats.messages.senderId",
"to": "objectId",
}
}
}
},
{
"$lookup": {
"from": "users",
"localField": "chats.messages.senderIdObjId",
"foreignField": "_id",
"as": "chats.messages.sender"
}
},
{
"$unwind": "$chats.messages.sender"
},
{
"$group": {
"_id": "$chats.id",
"messages": {
"$push": "$chats.messages"
},
"allFields": {
"$first": "$$ROOT"
}
}
},
{
"$addFields": {
"allFields.chats.messages": "$messages"
}
},
{
"$replaceWith": "$allFields"
},
{
"$group": {
"_id": "$_id",
"chats": {
"$push": "$chats"
},
"allFields": {
"$first": "$$ROOT"
}
}
},
{
"$addFields": {
"allFields.chats": "$chats"
}
},
{
"$replaceWith": "$allFields"
},
])
Working Playground here
I don't know if it's either possible but I would like to obtain a specific output from an aggregate pipeline.
Exemples objects:
{
"_id": "6001d736e6dc1c55e893158d",
"manager": "6000da590ed6253807158216",
"label": "Test",
"identifier": "Test",
"interval": 11,
"unit": "X",
"created_at": "2021-01-15T17:56:06.749Z",
"updated_at": "2021-01-21T12:21:35.670Z",
"__v": 0
},
{
"_id": "6030236f976756b0b2d74556",
"manager": "6022f3285752fec73393bda2",
"label": "Temperature salon",
"identifier": "DS18B20_TEMP",
"interval": 60,
"unit": "°C",
"created_at": "2021-02-19T20:45:35.847Z",
"updated_at": "2021-02-19T20:45:35.847Z",
"__v": 0
}
I'm trying to obtain a group by date AND by unit(field in object), i succeed to do it separatly but i can't find a solution to do both in the same pipeline.
Expected output if i do the first group by month:
{
"_id": "2021-01-00T00:00:00.000Z",
"X": objectsArray[],
"°C": objetcsArray[]
},
{
"_id": "2021-02-00T00:00:00.000Z",
"X": objectsArray[],
"°C": objetcsArray[]
}
What i have for the moment with this group:
{
'_id': {
'$add': [
{ '$subtract': [
{ '$subtract': [ '$created_at', new Date(0) ] },
{ '$mod': [
{ '$subtract': [ '$created_at', new Date(0) ] },
this.millisecondsIn(interval),
]},
]},
new Date(0),
]
},
sensors: {
$addToSet: '$$ROOT',
},
}
{
"_id": "2021-01-21T00:00:00.000Z",
"sensors": [
{
"_id": "601ab8f623224a5387c6252d",
"manager": "6000da590ed6253807158216",
"label": "Test",
"identifier": "Test2",
"interval": 60,
"unit": "°C",
"created_at": "2021-02-03T14:53:42.538Z",
"updated_at": "2021-02-03T14:53:42.538Z",
"__v": 0
},
{
"_id": "6029ad3dda9bafb99cf0b4d5",
"manager": "6022f3285752fec73393bda2",
"label": "Test sensor 1",
"identifier": "RANDOMID",
"interval": 60,
"unit": "°C",
"created_at": "2021-02-14T23:07:41.255Z",
"updated_at": "2021-02-14T23:07:41.255Z",
"__v": 0
}
]
},
{
"_id": "2020-12-24T00:00:00.000Z",
"sensors": [
{
"_id": "6001917f41c38212a477a2ce",
"manager": "6000da590ed6253807158216",
"label": "Test label",
"identifier": "TEst id",
"interval": 10,
"unit": "%",
"created_at": "2021-01-15T12:58:39.514Z",
"updated_at": "2021-01-16T19:08:40.239Z",
"__v": 0
},
{
"_id": "6001d736e6dc1c55e893158d",
"manager": "6000da590ed6253807158216",
"label": "Test",
"identifier": "Test",
"interval": 11,
"unit": "X",
"created_at": "2021-01-15T17:56:06.749Z",
"updated_at": "2021-01-21T12:21:35.670Z",
"__v": 0
}
]
},
{
"_id": "2021-02-18T00:00:00.000Z",
"sensors": [
{
"_id": "6030238d976756b0b2d74557",
"manager": "6022f3285752fec73393bda2",
"label": "Taux d'humidité salon",
"identifier": "DHT_22_HUM",
"interval": 60,
"unit": "%",
"created_at": "2021-02-19T20:46:05.042Z",
"updated_at": "2021-02-19T20:46:05.042Z",
"__v": 0
},
{
"_id": "60302357976756b0b2d74555",
"manager": "6022f3285752fec73393bda2",
"label": "Temperature salon",
"identifier": "DTH_22_TEMP",
"interval": 60,
"unit": "°C",
"created_at": "2021-02-19T20:45:11.071Z",
"updated_at": "2021-02-19T20:45:11.071Z",
"__v": 0
},
{
"_id": "6030236f976756b0b2d74556",
"manager": "6022f3285752fec73393bda2",
"label": "Temperature salon",
"identifier": "DS18B20_TEMP",
"interval": 60,
"unit": "°C",
"created_at": "2021-02-19T20:45:35.847Z",
"updated_at": "2021-02-19T20:45:35.847Z",
"__v": 0
}
]
}
Does anyone know if the wanted output is possible and if it is, how ?
Thanks
The general steps would be:
$group by unit and date, pushing all of the documents into a sensors array
$project to create a new field with {k: <unit value>, v: <sensors array>}
$group by date, pushing the new field into an array
$project with $arrayToObject to convert array
$addFields to include the date in the new object
$replaceRoot to promote the new object
Thank you so much Joe, after few hours and many tries I end up with this:
this.sensorModel
.aggregate()
.group({
'_id': {
date: { '$year': '$created_at' },
'unit': '$unit',
},
test: { '$addToSet': '$$ROOT' },
})
.project({
newField: {
k: '$_id.unit',
v: '$test',
}
})
.group({
'_id': '$_id.date',
data: { '$addToSet': '$newField', },
})
.project({
'sensors': { $arrayToObject: '$data', },
})
.replaceRoot({
$arrayToObject: [[{k: {$toString: '$_id'}, v: '$sensors'}]]
})
.exec();
The result is almost perfect:
[
{
"2021": {
"°C": [
{
"_id": "6029ad3dda9bafb99cf0b4d5",
"manager": "6022f3285752fec73393bda2",
"label": "Test sensor 1",
"identifier": "RANDOMID",
"interval": 60,
"unit": "°C",
"created_at": "2021-02-14T23:07:41.255Z",
"updated_at": "2021-02-14T23:07:41.255Z",
"__v": 0
},
],
"X": [
{
"_id": "6001d736e6dc1c55e893158d",
"manager": "6000da590ed6253807158216",
"label": "Test",
"identifier": "Test",
"interval": 11,
"unit": "X",
"created_at": "2021-01-15T17:56:06.749Z",
"updated_at": "2021-01-21T12:21:35.670Z",
"__v": 0
}
],
"%": [
{
"_id": "6030238d976756b0b2d74557",
"manager": "6022f3285752fec73393bda2",
"label": "Taux d'humidité salon",
"identifier": "DHT_22_HUM",
"interval": 60,
"unit": "%",
"created_at": "2021-02-19T20:46:05.042Z",
"updated_at": "2021-02-19T20:46:05.042Z",
"__v": 0
},
]
}
}
]
I have the collection data from a csv file with header. When i run my query
db.ties.aggregate(
[
{
$group:
{
_id: { "SHOP": "$SHOP" },
isLinkedTo: { $push: { "PERSON": "$PERSON", "CITY": "$CITY", "ROOM": "$ROOM", "STYLE": "$STYLE", "hasDonated": {"DATE": "$DATE", "OBJECT": "$OBJECT", "COST": "$COST", "COLOR": "$COLOR", "PAYMENT": "$PAYMENT"}}}
}
},
{ $out: "ties"}
],
{ allowDiskUse: true }
)
I have like result:
{
"_id": {
"Shop": "FirstShopNameCovered"
},
"isLinkedTo": [{
"PERSON": "Carleen",
"CITY": "Rome",
"ROOM": "Kitchen",
"STYLEPREFERED": "Modern",
"hasDonated": {
"DATE": "2019-10-11",
"OBJECT": "Set of dishes",
"COST": 72,
"COLOR": "White",
"PAYMENT": "Credit card"
}
}, {
"PERSON": "Carleen",
"CITY": "Rome",
"ROOM": "Kitcher",
"STYLEPREFERED": "Modern",
"hasDonated": {
"DATE": "2018-10-26",
"OBJECT": "Set of chairs",
"COST": 353,
"COLOR": "Grey",
"PAYMENT": "Coupon"
}
}, {
"PERSON": "Pernick",
"CITY": "Venezia",
"ROOM": "Bathroom",
"STYLE": "Minimalist",
"hasDonated": {
"DATE": "2018-09-18",
"OBJECT": "Mirror",
"COST": 68,
"COLOR": "Brown",
"PAYMENT": "Credit card"
}
}
You can see that there is replicated the Person "PERSON": "Carleen" with all data with 2 different arrays hasDonated.
I wish have something like this result, with person not replicated that contains all hasDonated arrays where he is present:
"_id": {
"Shop": "NameCovered"
},
"isLinkedTo": [{
"PERSON": "Carleen",
"CITY": "Rome",
"ROOM": "Kitchen",
"STYLE": "Retrò",
"hasDonated": {
"DATE": "2019-10-11",
"OBJECT": "Set of dishes",
"COST": 72,
"COLOR": "White",
"PAYMENT": "Credit card"
},
{
"DATE": "2018-10-26",
"OBJECT": "Chair",
"COST": 53,
"COLOR": "Grey",
"PAYMENT": "Coupon"
}
}, {
"PERSON": "Pernick",
"CITY": "Venezia",
"ROOM": "Bathroom",
"STYLE": "Minimalist",
"hasDonated": {
"DATE": "2018-09-18",
"OBJECT": "Mirror",
"COST": 68,
"COLOR": "Brown",
"PAYMENT": "Credit card"
}
How can I do to have the result like this?
First we need to $unwind to flat the array. Then group the hasDonated using $group where unique is found by combination of "_id" and "PERSON" as you mentioned.
[
{
"$unwind": "$isLinkedTo"
},
{
$group: {
_id: {
_id: "$_id",
per: "$isLinkedTo.PERSON"
},
isLinkedTo: {
$first: {
PERSON: "$isLinkedTo.PERSON",
CITY: "$isLinkedTo.CITY",
ROOM: "$isLinkedTo.ROOM",
STYLEPREFERED: "$isLinkedTo.STYLEPREFERED"
}
},
hasDonated: {
$addToSet: "$isLinkedTo.hasDonated"
}
}
},
{
$addFields: {
_id: "$_id._id",
"isLinkedTo.hasDonated": "$hasDonated"
}
},
{
$project: {
hasDonated: 0
}
},
{
$group: {
_id: "$_id",
isLinkedTo: {
$push: "$isLinkedTo"
}
}
}
]
Working Mongo playground
I have two collections, products and orders.
products collection look like this.
[
{
"_id": "5efb56741c32133bf43ea9aa",
"title": "Xyz",
"image": "172e4eb73415b3cc8540e651.jpg",
"quantity": "1 Ltr",
"price": 1500,
"status": true,
"creationDate": "2020-06-30T15:12:52.570Z",
"__v": 0
},
{
"_id": "5f0079bd27a734424cb3069a",
"title": "abc",
"image": "122e4eb73413b3cc854n42n1.jpg",
"quantity": "500 ml",
"price": 700,
"status": true,
"creationDate": "2020-06-30T15:12:52.570Z",
"__v": 0
}
]
orders collection look like this.
[
{
"_id": "5efca937def27b74fc9f6aa6",
"products": [
{
"Date": "2020-07-01T15:14:36.630Z",
"_id": "5efca937def27b74fc9f6aa8",
"productId": "5efb56741c32133bf43ea9aa",
"productQuantity": 2
},
{
"Date": "2020-07-01T15:14:36.630Z",
"_id": "5efca937def27b74fc9f6aa7",
"productId": "5f0079bd27a734424cb3069a",
"productQuantity": 1
}
],
"totalQuantity": 3,
"totalPrice": 3700,
"creationDate": "2020-07-01T15:18:15.756Z",
"__v": 0
},
{
"_id": "5efca897def27b74fc9f6aa2",
"products": [
{
"Date": "2020-07-01T15:14:36.630Z",
"_id": "5efca897def27b74fc9f6aa3",
"productId": "5f0079bd27a734424cb3069a",
"productQuantity": 1
}
],
"totalQuantity": 1,
"totalPrice": 700,
"creationDate": "2020-07-01T15:15:35.422Z",
"__v": 0
}
]
using this two collections how can I get result like this:
[
{
"_id": "5efca937def27b74fc9f6aa6",
"products": [
{
"Date": "2020-07-01T15:14:36.630Z",
"_id": "5efca937def27b74fc9f6aa8",
"productId": "5efb56741c32133bf43ea9aa",
"productQuantity": 2,
"title": "Xyz",
"image": "172e4eb73415b3cc8540e651.jpg",
"quantity": "1 Ltr",
"price": 1500
},
{
"Date": "2020-07-01T15:14:36.630Z",
"_id": "5efca937def27b74fc9f6aa7",
"productId": "5f0079bd27a734424cb3069a",
"productQuantity": 1,
"title": "abc",
"image": "122e4eb73413b3cc854n42n1.jpg",
"quantity": "500 ml",
"price": 700
}
],
"totalQuantity": 3,
"totalPrice": 3700,
"creationDate": "2020-07-01T15:18:15.756Z",
"__v": 0
},
{
"_id": "5efca897def27b74fc9f6aa2",
"products": [
{
"Date": "2020-07-01T15:14:36.630Z",
"_id": "5efca897def27b74fc9f6aa3",
"productId": "5f0079bd27a734424cb3069a",
"productQuantity": 1,
"title": "abc",
"image": "122e4eb73413b3cc854n42n1.jpg",
"quantity": "500 ml",
"price": 700
}
],
"totalQuantity": 1,
"totalPrice": 700,
"creationDate": "2020-07-01T15:15:35.422Z",
"__v": 0
}
]
I got the result using this query.
order.aggregate([
{ "$unwind": "$products" },
{
$lookup: {
from: 'products',
localField: "products.productId",
foreignField: "_id",
as: "product"
}
},
{
"$addFields": {
"products": { $mergeObjects: [{ $arrayElemAt: ["$product", 0] }, "$$ROOT.products"] }
}
},
{
"$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"totalQuantity": { $first: '$totalQuantity' },
"totalPrice": { $first: '$totalPrice' },
"creationDate": { $first: '$creationDate' }
}
}
])