I am trying to do groupBy with a population operation in MongoDB with Mongoose and Node.js.
I have one separate collection which is holding client_id and project_id. One client can have many projects, that's why I have created another collection for better understanding:
var CustomerHasProjectSchema = new mongoose.Schema({
client_id: {type: mongoose.Schema.Types.ObjectId, ref: 'Customer'},
project_id: {type: mongoose.Schema.Types.ObjectId, ref: 'Project'},
txn_date: {
type: Date,
default: Date.now
},
status: {
type: Number,
default : 1
}
});
I am trying to do something like
groupby(client_id)
and populate(user_id)
The exact query I have tried is
return customerHasProject.aggregate(
[
{
$match: {
$and: [
{ client_id: id }
]
}
},
{
$group : {
_id : "$client_id",
count: {
$sum: 1
}
}
},
{
$lookup: {
from: "project",
localField: "project_id",
foreignField: "_id",
as: "projects"
}
},
{
$unwind : {
"path" : "$project_id"
}
}
]
I tried this with help from another StackOverflow post.
I have also tried:
return customer2.default.find({'_id' : req.params.id}).exec().then(response=>{
project2.default.find({'client_id' : response[0]._id}).populate('client_id').then(customerWithProject=>{
res.json(customerWithProject)
})
})
But this is returning client detail in every project with a result like:
[
{
_id: "5883b189872c7d00042e1630",
projectTitle: "Marketing Analytics",
client_id: {
_id: "58833d9e1079ba000445a3a1",
clientName: "Anil",
companyName: "fgjhtrjhed",
website: "jhtryjh",
clientEmail: "frhyrt#tyhtr.dfkgjoiu",
mobileNumber: 549821654,
companyLocation: "New Delhi, Delhi, India",
clientCategory: "Freelancer",
__v: 0,
status: 1,
txn_date: "2017-01-21T10:53:18.360Z"
},
start_date: "2017-01-21T18:30:00.000Z",
end_date: "2017-01-30T18:30:00.000Z",
domain: "Back to the Future",
proposed_amount: 138000,
expectedFinalAmount: 200000,
__v: 0,
status: 1,
txn_date: "2017-01-21T19:07:53.214Z",
keywords: [
"JavaScript",
"AngularJs",
"C"
]
},
{
_id: "5883b213872c7d00042e1631",
projectTitle: "Indus Milk",
client_id: {
_id: "58833d9e1079ba000445a3a1",
clientName: "Anil",
companyName: "fgjhtrjhed",
website: "jhtryjh",
clientEmail: "frhyrt#tyhtr.dfkgjoiu",
mobileNumber: 549821654,
companyLocation: "New Delhi, Delhi, India",
clientCategory: "Freelancer",
__v: 0,
status: 1,
txn_date: "2017-01-21T10:53:18.360Z"
},
domain: "Back to the Future",
start_date: "2017-01-01T18:30:00.000Z",
end_date: "2017-01-06T18:30:00.000Z",
proposed_amount: 9200,
expectedFinalAmount: 15000,
__v: 0,
status: 1,
txn_date: "2017-01-21T19:10:11.403Z",
keywords: [
"Java",
"JavaScript"
]
},
{
_id: "5883b817872c7d00042e1632",
proposed_amount: 120000,
start_date: "2017-01-09T18:30:00.000Z",
end_date: "2017-02-03T18:30:00.000Z",
domain: "Back to the Future",
client_id: {
_id: "58833d9e1079ba000445a3a1",
clientName: "Anil",
companyName: "fgjhtrjhed",
website: "jhtryjh",
clientEmail: "frhyrt#tyhtr.dfkgjoiu",
mobileNumber: 549821654,
companyLocation: "New Delhi, Delhi, India",
clientCategory: "Freelancer",
__v: 0,
status: 1,
txn_date: "2017-01-21T10:53:18.360Z"
},
projectTitle: "Something",
__v: 0,
status: 1,
txn_date: "2017-01-21T19:35:51.835Z",
keywords: [
"C++",
"C"
]
}
]
Expecting something like
[
{
client_id: {
_id: "58833d9e1079ba000445a3a1",
clientName: "Anil",
companyName: "fgjhtrjhed",
website: "jhtryjh",
clientEmail: "frhyrt#tyhtr.dfkgjoiu",
mobileNumber: 549821654,
companyLocation: "New Delhi, Delhi, India",
clientCategory: "Freelancer",
__v: 0,
status: 1,
txn_date: "2017-01-21T10:53:18.360Z"
},
project_id : [
{
_id: "5883b213872c7d00042e1631",
projectTitle: "Indus Milk",
domain: "Back to the Future",
start_date: "2017-01-01T18:30:00.000Z",
end_date: "2017-01-06T18:30:00.000Z",
proposed_amount: 9200,
expectedFinalAmount: 15000,
},{
_id: "5883b817872c7d00042e1632",
proposed_amount: 120000,
start_date: "2017-01-09T18:30:00.000Z",
end_date: "2017-02-03T18:30:00.000Z",
domain: "Back to the Future",
projectTitle: "Something",
expectedFinalAmount: 15000,
}
]
}
]
Related
I have 2 tables booking and parking. In the booking table there is parkingId which refers to parking model. In the parking model there is a field named availability which is following:
[
{
"day": "Monday",
"startTime": "09:00",
"endTime": "17:00",
},
{... //Other days}
]
I want to unwind the availability array.
I have tried this:
let startTime = await Booking.aggregate([
{
$match: { _id: new mongoose.Types.ObjectId(req.params.id) },
},
{
$lookup: {
from: "parkings",
localField: "parkingId",
foreignField: "_id",
as: "parking",
},
},
{
$unwind: "$parking",
},
{ $unwind: "$parking.availability" },
]);
But it logs the result 6 times because there are 6 objects in the availability array like following.
[{
_id: new ObjectId("62e8ac3943a6bfaf80de75b5"),
parkingId: new ObjectId("62e11ab3079daa939290fa07"),
user: new ObjectId("62c950dfc96c2b690028be88"),
date: 2022-07-26T00:00:00.000Z,
startTime: 2022-07-26T09:30:00.000Z,
duration: { days: 0, hours: 2, minutes: 0 },
endTime: 2022-07-26T11:30:00.000Z,
isFeePaid: false,
status: 'sent',
isBookingCancelled: { value: false },
isStarted: false,
isEnabled: false,
parking: {
_id: new ObjectId("62e11ab3079daa939290fa07"),
userId: new ObjectId("62c950dfc96c2b690028be88"),
contactInfo: [Object],
about: 'Nisi occaecat ipsum',
parkingImage: [],
location: [Array],
price: 5,
availability: [Object],
parkingType: 'residence',
parkingInfo: [Array],
totalSpots: 10,
coordinates: [Object],
status: 'active',
isFeePaid: false,
}
},
]
I want only availability data but it prints availability: [Object]
I have a mongoDB collection as below
[
{
_id: ObjectId("60a245f4b828e75b584cdb12"),
Name: "Ayaan Ansari",
UserName: "anaan123#gmail.com",
Mobile: "055",
Addr1: "P . O . Box ",
Addr2: "Ajman",
Addr3: "",
CompanyName: "Ayaan Technical Services LLC",
Location: "Sharjah",
TelNo: "055",
mailID: "anaan123#gmail.com",
status: "true",
userRole: "customer",
supplierList: [
{
supplierid: "60a0221697727e0108a25c0d",
approved: false,
},
],
},
{
_id: ObjectId("60a2562b194fed38e86d01f4"),
Name: "Amaan Ansari",
UserName: "amaan123#gmail.com",
Mobile: "055",
Addr1: "P . O . Box",
Addr2: "Ajman",
Addr3: "",
CompanyName: "Amaan Technical Services LLC",
Location: "Umm Al Qwain",
TelNo: "055",
mailID: "amaan123#gmail.com",
status: "true",
userRole: "customer",
supplierList: [
{
supplierid: "60a0221697727e0108a25c0d",
approved: false,
},
{
supplierid: "60953b6029b7082214db84e4",
approved: false,
},
],
},
{
_id: ObjectId("60a295491086c054d83bf82e"),
Name: "Shaji Kalangoth",
UserName: "shaji#shaji.com",
Mobile: "00",
Addr1: "P . O . Box ",
Addr2: "Ajman",
Addr3: "",
CompanyName: "Shaji IT Services LLC",
Location: "Abu Dhabi",
TelNo: "00",
mailID: "00",
status: "true",
userRole: "customer",
},
]
When I use below query in 3T Studio I am getting correct result what I need
db.getCollection("user").find(
{
userRole: "customer",
},
{
supplierList: {
$elemMatch: {
supplierid: "60953b6029b7082214db84e4",
approved: false,
},
},
Name: 1,
UserName: 1,
Mobile: 1,
CompanyName: 1,
Location: 1,
userRole: 1,
},
);
Resullt :-
[
{
_id: ObjectId("60a245f4b828e75b584cdb12"),
Name: "Ayaan Ansari",
UserName: "anaan123#gmail.com",
Mobile: "055",
CompanyName: "Ayaan Technical Services LLC",
Location: "Sharjah",
userRole: "customer",
},
{
_id: ObjectId("60a2562b194fed38e86d01f4"),
Name: "Amaan Ansari",
UserName: "amaan123#gmail.com",
Mobile: "055",
CompanyName: "Amaan Technical Services LLC",
Location: "Umm Al Qwain",
userRole: "customer",
supplierList: [
{
supplierid: "60953b6029b7082214db84e4",
approved: false,
},
],
},
{
_id: ObjectId("60a295491086c054d83bf82e"),
Name: "Shaji Kalangoth",
UserName: "shaji#shaji.com",
Mobile: "00",
CompanyName: "Shaji IT Services LLC",
Location: "Abu Dhabi",
userRole: "customer",
},
]
but when i use in node js the second document shows all objects but i need to show only one object which fulfilling the criteria. in 3T Studio the code working fine and getting only the required array object.
let allCustomers = await db
.get()
.collection(collection.USER_COLLECTION)
.find(
{
userRole: "customer",
},
{
supplierList: {
$elemMatch: {
supplierid: "60953b6029b7082214db84e4",
approved: false,
},
},
Name: 1,
UserName: 1,
Mobile: 1,
CompanyName: 1,
Location: 1,
userRole: 1,
},
)
.toArray();
The result : -
[
{
_id: ObjectId("60a245f4b828e75b584cdb12"),
Name: "Ayaan Ansari",
UserName: "anaan123#gmail.com",
Mobile: "055",
CompanyName: "Ayaan Technical Services LLC",
Location: "Sharjah",
userRole: "customer",
supplierList: [
{
supplierid: "60a0221697727e0108a25c0d",
approved: false,
},
],
},
{
_id: ObjectId("60a2562b194fed38e86d01f4"),
Name: "Amaan Ansari",
UserName: "amaan123#gmail.com",
Mobile: "055",
CompanyName: "Amaan Technical Services LLC",
Location: "Umm Al Qwain",
userRole: "customer",
supplierList: [
{
supplierid: "60a0221697727e0108a25c0d",
approved: false,
},
{
supplierid: "60953b6029b7082214db84e4",
approved: false,
},
],
},
{
_id: ObjectId("60a295491086c054d83bf82e"),
Name: "Shaji Kalangoth",
UserName: "shaji#shaji.com",
Mobile: "00",
CompanyName: "Shaji IT Services LLC",
Location: "Abu Dhabi",
userRole: "customer",
},
]
I don't know why this result is deferent please someone help me to solve this please .....
In Node
Query:-
let allCustomers = await db.get().collection("user").find({ userRole: "customer" })
.project({
supplierList: {
$elemMatch: {
supplierid: "60953b6029b7082214db84e4",
approved: false,
},
},
Name: 1,
UserName: 1,
Mobile: 1,
CompanyName: 1,
Location: 1,
userRole: 1,
})
.toArray();
Result: -
[
{
_id: 60a3e64e8237c52d04dbde9a,
Name: 'Ayaan Ansari',
UserName: 'anaan123#gmail.com',
Mobile: '055',
CompanyName: 'Ayaan Technical Services LLC',
Location: 'Sharjah',
userRole: 'customer'
},
{
_id: 60a3e64e8237c52d04dbde9b,
Name: 'Amaan Ansari',
UserName: 'amaan123#gmail.com',
Mobile: '055',
CompanyName: 'Amaan Technical Services LLC',
Location: 'Umm Al Qwain',
userRole: 'customer',
supplierList: [ [Object] ]
},
{
_id: 60a3e64e8237c52d04dbde9c,
Name: 'Shaji Kalangoth',
UserName: 'shaji#shaji.com',
Mobile: '00',
CompanyName: 'Shaji IT Services LLC',
Location: 'Abu Dhabi',
userRole: 'customer'
}
]
Happy Coding 😁
let allCustomers = await db.get().collection("user").find({ userRole: "customer" })
.project({
supplierList: {
$elemMatch: {
supplierid: "60953b6029b7082214db84e4",
approved: false,
},
},
Name: 1,
UserName: 1,
Mobile: 1,
CompanyName: 1,
Location: 1,
userRole: 1,
})
.toArray();
Thank you .....
I want to aggregate the collections (Review and Account) below but couldn't manage it properly so I needed to ask you guys.
Current Review Collection is written below
{
lawyerId: { type: mongoose.Schema.Types.ObjectId },
reviews: [
{
userId: { type: mongoose.Schema.Types.ObjectId, unique: true },
message: { type: String },
rate: { type: Number },
createdAt: { type: Date, default: Date.now },
},
],
}
If you recommend Review Collection can be refactored like this
{
lawyerId: { type: mongoose.Schema.Types.ObjectId },
userId: { type: mongoose.Schema.Types.ObjectId },
message: { type: String },
rate: { type: Number },
createdAt: { type: Date, default: Date.now },
}
Account Collection
{
_id: { type: mongoose.Schema.Types.ObjectId}
email: { type: String, unique: true },
firstName: { type: String },
lastName: { type: String },
},
The expected result of fetching reviews
{
averageRate: 3.2,
reviews: [
{
firstName: 'Jack',
lastName: 'Harden',
message: 'I dont like it',
rate: 2,
createdAt: '2020-01-01T14:58:23.330+00:00'
},
{
firstName: 'Takeshi',
lastName: 'San',
message: 'Thats nice',
rate: 5,
createdAt: '2020-03-02T10:45:10.120+00:00'
}
],
}
You should be able to achieve this using an aggregation.
You can view a live demo here, which allows you to run this query.
The Query:
// Assuming we are searching for an lawyerId of 3
db.review.aggregate([
{
$match: {
lawyerId: 3
}
},
{
$lookup: {
from: "account",
localField: "userId",
foreignField: "_id",
as: "user"
}
},
{
$unwind: "$user"
},
{
$group: {
_id: "$lawyerId",
averageRate: {
$avg: "$rate"
},
reviews: {
$push: {
createdAt: "$createdAt",
firstName: "$user.firstName",
lastName: "$user.lastName",
message: "$message",
rate: "$rate"
}
}
}
},
{ // *******************************************
$project: { // *******************************************
_id: 0, // If you comment out/remove all of these lines
averageRate: 1, // then the return also contains the 'lawyerId',
reviews: 1 // as '_id', which I would find useful...
} // *******************************************
} // *******************************************
])
The Results:
The query from above, using the data set from above, produces the following results:
[
{
"averageRate": 3.25,
"reviews": [
{
"createdAt": ISODate("2015-02-28T00:00:00Z"),
"firstName": "First",
"lastName": "Uno",
"message": "Message meh",
"rate": 3
},
{
"createdAt": ISODate("2015-02-28T00:00:00Z"),
"firstName": "Second",
"lastName": "Dos",
"message": "Message blah",
"rate": 4
},
{
"createdAt": ISODate("2015-02-28T00:00:00Z"),
"firstName": "First",
"lastName": "Uno",
"message": "Message foo",
"rate": 4
},
{
"createdAt": ISODate("2015-02-28T00:00:00Z"),
"firstName": "Third",
"lastName": "Tres",
"message": "Message bar",
"rate": 2
}
]
}
]
The Dataset:
In Mongo Playground, you can build out databases with multiple collections, this explains the data structure:
db={ // <---- Database 'db'
"account": [ // <---- Collection 'account'
{
_id: 21,
email: "first.uno#gmail.com",
firstName: "First",
lastName: "Uno"
},
{
_id: 22,
email: "second.dos#yahoo.com",
firstName: "Second",
lastName: "Dos"
},
{
_id: 23,
email: "third.tres#hotmail.com",
firstName: "Third",
lastName: "Tres"
}
],
"review": [ // <---- Collection 'review'
{
lawyerId: 3,
userId: 21,
message: "Message meh",
rate: 3,
createdAt: ISODate("2015-02-28T00:00:00Z")
},
{
lawyerId: 3,
userId: 22,
message: "Message blah",
rate: 4,
createdAt: ISODate("2015-02-28T00:00:00Z")
},
{
lawyerId: 3,
userId: 21,
message: "Message foo",
rate: 4,
createdAt: ISODate("2015-02-28T00:00:00Z")
},
{
lawyerId: 3,
userId: 23,
message: "Message bar",
rate: 2,
createdAt: ISODate("2015-02-28T00:00:00Z")
}
]
}
You can try this pipeline to get all reviews from review collection:
db.reviews.aggregate([
{
$lookup: {
from: "accounts",
localField: "userId",
foreignField: "_id",
as: "user"
}
},
{
$unwind: "$user"
},
{
$addFields: {
"firstName": "$user.firstName",
"lastName": "$user.lastName"
}
},
{
$group: {
"_id": null,
"average_rate": {
$avg: "$rate"
},
"reviews": {
$push: "$$ROOT"
}
}
},
{
$unset: [
"_id",
"reviews._id",
"reviews.user",
"reviews.userId",
"reviews.lawyerId"
]
}
])
Results:
[
{
"average_rate": 3.5,
"reviews": [
{
"createdAt": "Some Review Date",
"firstName": "Jack",
"lastName": "Harden",
"message": "I dont like it",
"rate": 2
},
{
"createdAt": "Some Review Date",
"firstName": "Takeshi",
"lastName": "San",
"message": "That's nice",
"rate": 5
}
]
}
]
Demo here
I am not able to sort the nested array. I have referred many links such as link 1 but still I haven't got proper solution for my problem.
Here is my JSON data:
{
_id: "5a8bf7e3903cc83237ebd014",
prospect_name: "Akruthi",
phone: "9878979879",
email: "",
address: "Kundapur",
landmark: "Grt",
city: "Udupi",
state: "5a869c795eb34ecae3ab1ef6",
region: "5a8689725eb34ecae3ab1ede",
methodology: 2,
sub_category: "colour",
created_by: "asdadasad",
referred_by: "Self",
remarks: [
{
data: "Good",
user: "5a8c0642903cc83237ebd01f",
created_at: "2018-02-20T10:26:43.686Z",
remarksId: "5a8bf7e3903cc83237ebd013",
},
{
data: "test 1",
user: "5a858129e6e8f6724d6aa551",
created_at: "2018-02-21T04:35:30.615Z",
remarksId: "5a8cf7122ad6f00da98a3f05",
},
{
data: "test 2",
user: "5a858129e6e8f6724d6aa551",
created_at: "2018-02-21T04:41:45.514Z",
remarksId: "5a8cf889160046121e3f1b25",
},
{
data: "test 3",
user: "5a858129e6e8f6724d6aa551",
created_at: "2018-02-21T04:54:01.018Z",
remarksId: "5a8cfb69ea4e7c14c1f7c550",
},
],
created_at: "2018-02-20T10:26:43.686Z"
}
I have done the following query in node.js:
return collection_name
.aggregate([
{ $match: { _id: objectid(id) } },
{ $lookup: { from: 'state', localField: 'state', foreignField: '_id', as: 'state_details' } },
{ $lookup: { from: 'region', localField: 'region', foreignField: '_id', as: 'region_details' } },
{ $lookup: { from: 'users', localField: 'remarks.user', foreignField: '_id', as: 'remarks_details' } },
{ $unwind: '$remarks' },
{ $sort: { 'remarks.created_at': -1 } },
{ $group: { _id: '$_id', remarks: { $push: '$remarks' } } },
])
and I got result as: (got the sorted result, but lost other fields)
{
_id: "5a8bf7e3903cc83237ebd014",
remarks: [
{
data: "test 3",
user: "5a858129e6e8f6724d6aa551",
created_at: "2018-02-21T04:54:01.018Z",
remarksId: "5a8cfb69ea4e7c14c1f7c550"
},
{
data: "test 2",
user: "5a858129e6e8f6724d6aa551",
created_at: "2018-02-21T04:41:45.514Z",
remarksId: "5a8cf889160046121e3f1b25"
},
{
data: "test 1",
user: "5a858129e6e8f6724d6aa551",
created_at: "2018-02-21T04:35:30.615Z",
remarksId: "5a8cf7122ad6f00da98a3f05"
},
{
data: "Good",
user: "5a8c0642903cc83237ebd01f",
created_at: "2018-02-20T10:26:43.686Z",
remarksId: "5a8bf7e3903cc83237ebd013"
}
]
}
In my result I lost all the other fields except remarks. I wanted the result along with other fields as well.. I tried $project operation but still it did not work.
expected result:
{
_id: "5a8bf7e3903cc83237ebd014",
prospect_name: "Akruthi",
phone: "9878979879",
email: "",
address: "Kundapur",
landmark: "Grt",
city: "Udupi",
state: "5a869c795eb34ecae3ab1ef6",
region: "5a8689725eb34ecae3ab1ede",
methodology: 2,
sub_category: "colour",
created_by: "asdadasad",
referred_by: "Self",
remarks: [
{
data: "test 3",
user: "5a858129e6e8f6724d6aa551",
created_at: "2018-02-21T04:54:01.018Z",
remarksId: "5a8cfb69ea4e7c14c1f7c550"
},
{
data: "test 2",
user: "5a858129e6e8f6724d6aa551",
created_at: "2018-02-21T04:41:45.514Z",
remarksId: "5a8cf889160046121e3f1b25"
},
{
data: "test 1",
user: "5a858129e6e8f6724d6aa551",
created_at: "2018-02-21T04:35:30.615Z",
remarksId: "5a8cf7122ad6f00da98a3f05"
},
{
data: "Good",
user: "5a8c0642903cc83237ebd01f",
created_at: "2018-02-20T10:26:43.686Z",
remarksId: "5a8bf7e3903cc83237ebd013"
}
],
created_at: "2018-02-20T10:26:43.686Z"
}
Add
{
$project:{
prospect_name: 1,
phone: 1,
email: 1,
address: 1,
landmark: 1,
city: 1,
state: 1,
region: 1,
methodology: 1,
sub_category: 1,
created_by: 1,
referred_by: 1
}
}
and replace your group by query with following line
{ $group: { _id: null, remarks: { $push: '$remarks' } } }
I am writing a request for statistics from the db. Here's the code:
Stats.aggregate([
{
$group: {
_id: {
'advertiser': '$advertiser',
'offer': '$offer'
},
stats: {
$push: {
'date': '$date',
'spent': '$spent',
'revenue': '$revenue'
}
}
}
},
{
$group: {
_id: '$_id.advertiser',
offers: {
$push: {
_id: '$_id.offer',
stats: '$stats'
}
}
}
}], callback);
I want that the advertiser had all his offers, and inside the offers there was statistics on the days along with spent and revenue. The problem is that statistics by day can be more than one and I get this answer:
stats […]
0 {…}
date 2018-01-30T22:00:00.000Z
spent 100
revenue 200
1 {…}
date 2018-01-30T22:00:00.000Z
spent 20
revenue 20
But, I need to have the same days folded into one and spent and revenue added
Also, I want to add offer info from offers collection into result offers, like I do with advertisers. Maybe someone know how to do this. Thank you
Stats in db:
{
"_id": {
"$oid": "5a4f873d381727000404d171"
},
"advertiser": {
"$oid": "5a4f74619f0251000438fe4a"
},
"offer": {
"$oid": "5a4f748c9f0251000438fe4b"
},
"spent": 415.19,
"revenue": 780.92,
"date": "2018-01-02T22:00:00.000Z",
"user": {
"$oid": "5a4f74259f0251000438fe40"
},
"__v": 0
}
Stats Schema
const StatsSchema = mongoose.Schema({
advertiser: {
type: ObjectId,
ref: 'Advertiser',
required: true
},
offer: {
type: ObjectId,
ref: 'Offer',
required: true
},
spent: {
type: Number,
required: true
},
revenue: {
type: Number,
required: true
},
date: {
type: String,
required: true
},
user: {
type: ObjectId,
ref: 'User',
required: true
}});
You can first project the day, month and year then group accordingly as below. This is a relatively long query you could add in some optimisations based on your workflow.
db.createCollection('statistics');
db.statistics.insertMany([
{advertiser: "1", offer: "1", date: "2018-01-30T22:00:00.000Z", spent: 10, revenue: 20},
{advertiser: "1", offer: "1", date: "2018-01-30T21:00:00.000Z", spent: 20, revenue: 20},
{advertiser: "2", offer: "2", date: "2018-01-30T22:00:00.000Z", spent: 10, revenue: 20},
{advertiser: "2", offer: "2", date: "2018-01-30T21:00:00.000Z", spent: 1000, revenue: 2000},
{advertiser: "2", offer: "2", date: "2018-01-31T22:00:00.000Z", spent: 25, revenue: 50}
])
transform_date = {
$project: {
advertiser: 1,
offer: 1,
date: { $dateFromString: { dateString: { $arrayElemAt: [ {$split: ["$date", "Z"]}, 0 ] }, timezone: 'UTC' } },
spent: 1,
revenue: 1
}
}
project_year_month_day = {
$project: {
advertiser: 1,
offer: 1,
date: 1,
spent: 1,
revenue: 1,
year: { $year: "$date" },
month: { $month: "$date" },
day: { $dayOfMonth: "$date" }
}
}
group_by_date_advertiser_offer_and_sum = {
$group: {
_id: {
advertiser: "$advertiser",
offer: "$offer",
day: "$day",
month: "$month",
year: "$year"
},
spent: { $sum: "$spent" },
revenue: { $sum: "$revenue" },
dates: { $push: "$date" }
}
}
group_advertiser_offer_and_push = {
$group: {
_id: {
advertiser: "$_id.advertiser",
offer: "$_id.offer"
},
stats: {
$push: {
dates: "$dates",
spent: "$spent",
revenue: "$revenue"
}
}
}
}
group_advertiser_and_push = {
$group: {
_id: "$_id.advertiser",
offers: {
$push: {
_id: "$_id.offer",
stats: "$stats"
}
}
}
}
db.statistics.aggregate([
transform_date,
project_year_month_day,
group_by_date_advertiser_offer_and_sum,
group_advertiser_offer_and_push,
group_advertiser_and_push
])
OUTPUT
[{
"_id": "2",
"offers": [{
"_id": "2",
"stats": [{
"dates": [ISODate("2018-01-31T22:00:00Z")],
"spent": 25,
"revenue": 50
}, {
"dates": [ISODate("2018-01-30T22:00:00Z"), ISODate("2018-01-30T21:00:00Z")],
"spent": 1010,
"revenue": 2020
}]
}]
} {
"_id": "1",
"offers": [{
"_id": "1",
"stats": [{
"dates": [ISODate("2018-01-30T22:00:00Z"), ISODate("2018-01-30T21:00:00Z")],
"spent": 30,
"revenue": 40
}]
}]
}]