MongoDB aggregate Timezone for date add - mongodb

I have a problem of MongoDB's aggregate of timezone is UTC. I have looked for solutions from many other existing issues, but it is still not working. My code as follows:
MongoDB version : 2.2
Data
{ "_id" : ObjectId("52a3c9df46c6a9627eeb0337"), "Counting" : { "id" : "b1a93dfda46c47848f9862031300d24c", "group" : "Salary", "user_id" : "4d4ad2d37a464ad09d9aca2fee4c760c", "subGroup" : "e–ae3?", "bank_id" : "97e0fecc322b49b48c4eb3c8425fea77", "fee" : 646, "isIncome" : "true", "payment" : "", "consumeDate" : ISODate("2013-08-15T16:00:00Z"), "createDate" : ISODate("2013-12-08T01:22:39.008Z"), "bank_name" : "9edb6897-cdb8-4ce4-8f08-f5792cfa83d9" } }
{ "_id" : ObjectId("52a3c9df46c6a9627eeb0338"), "Counting" : { "id" : "33b341fc71314daebe851397c5cbaa40", "group" : "Salary", "user_id" : "cb9e06649cf943e5b368f6b05fc126c6", "subGroup" : "e–ae3?", "bank_id" : "e8da8cdae3ae495ca76f873fb3460b6d", "fee" : 647, "isIncome" : "true", "payment" : "", "consumeDate" : ISODate("2013-02-28T16:00:00Z"), "createDate" : ISODate("2013-12-08T01:22:39.016Z"), "bank_name" : "6913b48a-1a95-48c5-81f5-6920031358d7"} }
{ "_id" : ObjectId("52a3c9df46c6a9627eeb033a"), "Counting" : { "id" : "f0d41ed9f29f47e7b68a05c378cf939d", "group" : "Salary", "user_id" : "847cadbf55f84615af3ee63922446b54", "subGroup" : "e–ae3?", "bank_id" : "f45d62b5e62f4b7fa8172870cd992f19", "fee" : 623, "isIncome" : "true", "payment" : "", "consumeDate" : ISODate("2013-04-18T16:00:00Z"), "createDate" : ISODate("2013-12-08T01:22:39.152Z"), "bank_name" : "30dd169e-723e-4748-93cd-2d7a45b4a3b7"} }
db.Product.aggregate([{
"$group": {
"_id": {
"tyear": {
"$year": [{
"$add": ["$Counting.consumeDate", 28800000]
}]
},
"tMonth": {
"$month": [{
"$add": ["$Counting.consumeDate", 28800000]
}]
},
"tDate": {
"$dayOfMonth": [{
"$add": ["$Counting.consumeDate", 28800000]
}]
},
},
"count": {
"$sum": "$Counting.fee"
}
} }])
Error Message :
"errmsg" : "exception: $add does not support dates"
Reference
How to agregate by year-month-day on a different timezone

I'd recommend doing this in two-steps as a project then a group.
var millisecondsFromUTC = 8 * 60 * 60 * 1000; //PST is -8 hours from UTC
db.Product.aggregate([
{ $project : {
consumeDateLocal: {
$subtract : [ "$Counting.consumeDate", millisecondsFromUTC ]
},
fee: '$Counting.fee" } },
{ $group: {
_id: {
"tyear": { $year: "$consumeDateLocal" },
"tMonth": { "$month": "$consumeDateLocal" },
"tDate": { "$dayOfMonth": "consumeDateLocal" }
},
count: {
$sum: "$fee"
}
} } ], ...);

I do it like this.
millisecondsFromUTC = 8 * 3600 * 1000
Db.collection.aggreagte([
{$match: query},
{
$group: {
_id: {
$dateToString: {
format: "%Y-%m-%d",
date: {$add: ["$date", millisecondsFromUTC]}
},
click: {$sum: '$click'},
money: {$sum: {$divide: ['$money', 10000]}},
pv: {$sum: '$pv'},
req: {$sum: '$req'},
date: {$last: '$date'}
}
}]

Related

Get sum of a column from mongodb along with the list of another column

I have a collection "employees" with sample entries as below-
{
"_id" : ObjectId("62ccaa238a322322211"),
"employeeId" : "1234",
"date" : ISODate("2022-07-11T12:00:00.000+0000"),
"hours" : 15.0,
"createdBy" : "user1",
"createdDate" : ISODate("2023-02-19T21:54:27.213+0000"),
"updatedBy" : "user1",
"updatedDate" : ISODate("2023-02-19T21:54:27.213+0000"),
},
{
"_id" : ObjectId("62ccaa238a322388821"),
"employeeId" : "1234",
"date" : ISODate("2022-07-10T12:00:00.000+0000"),
"hours" : 25.0,
"createdBy" : "user1",
"createdDate" : ISODate("2023-02-19T22:54:27.213+0000"),
"updatedBy" : "user1",
"updatedDate" : ISODate("2023-02-19T22:54:27.213+0000"),
}
I am trying to get sum of hours for each employee along with the list of dates for those entries
{
employeeId :"1234"
hours : 40 // sum of the hours from both entries
dates : [2022-07-11, 2022-07-10] // list of `date` column
}
I tried below one but dont know how to adapt to get employeeId and sum
db.getCollection("employees").aggregate( [
{ $match : {
$and :[
{"employeeId" : "1234"},
{"date" : { $lte: new ISODate("2023-02-19") }}
]}},
{
$group:
{
"_id": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$date"
}
},
totalAmount: { $sum: "$hours" }
}
}
] )
You should group by employeeId instead of date.
db.collection.aggregate([
{
$group: {
_id: "$employeeId",
hours: {
$sum: "$hours"
},
dates: {
$push: {
$dateTrunc: {
date: "$date",
unit: "day"
}
}
}
}
}
])
Mongo Playground

Filter by nested arrays/objects values (on different levels) and $push by multiple level - MongoDB Aggregate

I have a document with multiple level of embedded subdocument each has some nested array. Using $unwind and sort, do sorting based on day in descending and using push to combine each row records into single array. This Push is working only at one level means it allows only one push. If want to do the same things on the nested level and retains the top level data, got "errmsg" : "Unrecognized expression '$push'".
{
"_id" : ObjectId("5f5638d0ff25e01482432803"),
"name" : "XXXX",
"mobileNo" : 323232323,
"payroll" : [
{
"_id" : ObjectId("5f5638d0ff25e01482432801"),
"month" : "Jan",
"salary" : 18200,
"payrollDetails" : [
{
"day" : "1",
"salary" : 200,
},
{
"day" : "2",
"salary" : 201,
}
]
},
{
"_id" : ObjectId("5f5638d0ff25e01482432802"),
"month" : "Feb",
"salary" : 8300,
"payrollDetails" : [
{
"day" : "1",
"salary" : 300,
},
{
"day" : "2",
"salary" : 400,
}
]
}
],
}
Expected Result:
{
"_id" : ObjectId("5f5638d0ff25e01482432803"),
"name" : "XXXX",
"mobileNo" : 323232323,
"payroll" : [
{
"_id" : ObjectId("5f5638d0ff25e01482432801"),
"month" : "Jan",
"salary" : 18200,
"payrollDetails" : [
{
"day" : "2",
"salary" : 201
},
{
"day" : "1",
"salary" : 200
}
]
},
{
"_id" : ObjectId("5f5638d0ff25e01482432802"),
"month" : "Feb",
"salary" : 8300,
"payrollDetails" : [
{
"day" : "2",
"salary" : 400
},
{
"day" : "1",
"salary" : 300
}
]
}
],
}
Just day will be sorted and remaining things are same
I have tried but it got unrecognized expression '$push'
db.employee.aggregate([
{$unwind: '$payroll'},
{$unwind: '$payroll.payrollDetails'},
{$sort: {'payroll.payrollDetails.day': -1}},
{$group: {_id: '$_id', payroll: {$push: {payrollDetails:{$push:
'$payroll.payrollDetails'} }}}}])
It requires two time $group, you can't use $push operator two times in a field,
$group by main id and payroll id, construct payrollDetails array
$sort by payroll id (you can skip if not required)
$group by main id and construct payroll array
db.employee.aggregate([
{ $unwind: "$payroll" },
{ $unwind: "$payroll.payrollDetails" },
{ $sort: { "payroll.payrollDetails.day": -1 } },
{
$group: {
_id: {
_id: "$_id",
pid: "$payroll._id"
},
name: { $first: "$name" },
mobileNo: { $first: "$mobileNo" },
payrollDetails: { $push: "$payroll.payrollDetails" },
month: { $first: "$payroll.month" },
salary: { $first: "$payroll.salary" }
}
},
{ $sort: { "payroll._id": -1 } },
{
$group: {
_id: "$_id._id",
name: { $first: "$name" },
mobileNo: { $first: "$mobileNo" },
payroll: {
$push: {
_id: "$_id.pid",
month: "$month",
salary: "$salary",
payrollDetails: "$payrollDetails"
}
}
}
}
])
Playground

How to get percentage total of data with group by date in MongoDB

How to get percentage total of data with group by date in MongoDB ?
Link example : https://mongoplayground.net/p/aNND4EPQhcb
I have some collection structure like this
{
"_id" : ObjectId("5ccbb96706d1d47a4b2ced4b"),
"date" : "2019-05-03T10:39:53.108Z",
"id" : 166,
"update_at" : "2019-05-03T10:45:36.208Z",
"type" : "image"
}
{
"_id" : ObjectId("5ccbb96706d1d47a4b2ced4c"),
"date" : "2019-05-03T10:39:53.133Z",
"id" : 166,
"update_at" : "2019-05-03T10:45:36.208Z",
"type" : "image"
}
{
"_id" : ObjectId("5ccbb96706d1d47a4b2ced4d"),
"date" : "2019-05-03T10:39:53.180Z",
"id" : 166,
"update_at" : "2019-05-03T10:45:36.208Z",
"type" : "image"
}
{
"_id" : ObjectId("5ccbb96706d1d47a4b2ced4e"),
"date" : "2019-05-03T10:39:53.218Z",
"id" : 166,
"update_at" : "2019-05-03T10:45:36.208Z",
"type" : "image"
}
And I have query in mongodb to get data of collection, how to get percentage of total data. in bellow example query to get data :
db.name_collection.aggregate(
[
{ "$match": {
"update_at": { "$gte": "2019-11-04T00:00:00.0Z", "$lt": "2019-11-06T00:00:00.0Z"},
"id": { "$in": [166] }
} },
{
"$group" : {
"_id": {
$substr: [ '$update_at', 0, 10 ]
},
"count" : {
"$sum" : 1
}
}
},
{
"$project" : {
"_id" : 0,
"date" : "$_id",
"count" : "$count"
}
},
{
"$sort" : {
"date" : 1
}
}
]
)
and this response :
{
"date" : "2019-11-04",
"count" : 39
},
{
"date" : "2019-11-05",
"count" : 135
}
how to get percentage data total from key count ? example response to this :
{
"date" : "2019-11-04",
"count" : 39,
"percentage" : "22%"
},
{
"date" : "2019-11-05",
"count" : 135,
"percentage" : "78%"
}
You have to group by null to get total count and then use $map to calculate the percentage. $round will be a useful operator in such case. Finally you can $unwind and $replaceRoot to get back the same number of documents:
db.collection.aggregate([
// previous aggregation steps
{
$group: {
_id: null,
total: { $sum: "$count" },
docs: { $push: "$$ROOT" }
}
},
{
$project: {
docs: {
$map: {
input: "$docs",
in: {
date: "$$this.date",
count: "$$this.count",
percentage: { $concat: [ { $toString: { $round: { $multiply: [ { $divide: [ "$$this.count", "$total" ] }, 100 ] } } }, '%' ] }
}
}
}
}
},
{
$unwind: "$docs"
},
{
$replaceRoot: { newRoot: "$docs" }
}
])
Mongo Playground

Mongodb Interval Query

I have a mongodb database with a collection user_arrival. The documents look like:
{
"_id" : ObjectId("5e0431821d0f986bdb338e82"),
"location" : {
"uuid" : "b8e671f3-742e-4a24-ae3e-6cd543e7c5bb",
"name" : "London"
},
"time" : ISODate("2019-12-16T16:37:45.000Z"),
"actor" : {
"user" : {
"uuid" : "c42f7cbf-84a6-4912-b414-6afc873e229d",
"name" : "User 1"
}
}
},
{
"_id" : ObjectId("5e0431d31d0f986bdb338e83"),
"location" : {
"uuid" : "b8e671f3-742e-4a24-ae3e-6cd543e7c5bb",
"name" : "London"
},
"time" : ISODate("2019-12-16T17:00:00.000Z"),
"actor" : {
"user" : {
"uuid" : "c42f7cbf-84a6-4912-b414-6afc873e229d",
"name" : "User 1"
}
}
},
{
"_id" : ObjectId("5e0431e41d0f986bdb338e84"),
"location" : {
"uuid" : "b8e671f3-742e-4a24-ae3e-6cd543e7c5bb",
"name" : "London"
},
"time" : ISODate("2019-12-16T17:05:00.000Z"),
"actor" : {
"user" : {
"uuid" : "c42f7cbf-84a6-4912-b414-6afc873e229d",
"name" : "User 1"
}
}
},
{
"_id" : ObjectId("5e04320f1d0f986bdb338e85"),
"location" : {
"uuid" : "b8e671f3-742e-4a24-ae3e-6cd543e7c5bb",
"name" : "London"
},
"time" : ISODate("2019-12-16T17:06:00.000Z"),
"actor" : {
"user" : {
"uuid" : "d42f7cbf-84a6-4912-b414-6afc873e229d",
"name" : "User 2"
}
}
},
{
"_id" : ObjectId("5e0432191d0f986bdb338e86"),
"location" : {
"uuid" : "b8e671f3-742e-4a24-ae3e-6cd543e7c5bb",
"name" : "London"
},
"time" : ISODate("2019-12-16T17:15:00.000Z"),
"actor" : {
"user" : {
"uuid" : "d42f7cbf-84a6-4912-b414-6afc873e229d",
"name" : "User 2"
}
}
}
According to above documents
User 1 - First-time card scan at 16:37:45
User 1 - Second-time card scan at 17:00:00
User 1 - Third-time card scan at 17:05:00
User 2 - First-time card scan at 17:06:00
User 2 - Second-time card scan at 17:15:00
Mongodb Group Query
db.getCollection('test').aggregate([
{
$match: {
time: { $gt: new Date('2019-12-16T00:00:00.000Z'), $lte: new Date('2019-12-17T00:00:00.000Z') },
'location.uuid': 'b8e671f3-742e-4a24-ae3e-6cd543e7c5bb',
},
},
{
$group: {
_id: {
hour: { $hour: { date: '$time' } },
minute: {
$subtract: [
{ $minute: { date: '$time'} },
{ $mod: [{ $minute: '$time' }, 60] },
],
},
},
count: { $addToSet: '$actor.user.uuid' },
},
},
{
$project: {
start_time: { $add: ['$_id.hour', 0] },
end_time: { $add: ['$_id.hour', 1] },
total_user_arrivals: { $size: '$count' },
_id: 0,
},
},
])
When I execute the above MongoDB query below results get.
[{
"start_time" : 16.0,
"end_time" : 17.0,
"total_user_arrivals" : 1
},
{
"start_time" : 17.0,
"end_time" : 18.0,
"total_user_arrivals" : 2
}]
Expexted Result
User 1 first-time card scan between 16:00:00 to 17:00:00
User 2 first-time card scan between 17:00:00 to 18:00:00
[{
"start_time" : 16.0,
"end_time" : 17.0,
"total_user_arrivals" : 1
},
{
"start_time" : 17.0,
"end_time" : 18.0,
"total_user_arrivals" : 1
}]
Before grouping, you need to get the first transaction of the users.
db.getCollection('test').aggregate([
{
$match: {
time: { $gt: new Date('2019-12-16T00:00:00.000Z'), $lte: new Date('2019-12-17T00:00:00.000Z') },
'location.uuid': 'b8e671f3-742e-4a24-ae3e-6cd543e7c5bb',
},
},
{ $sort: { time: 1 } },
{
$group: {
_id: {
uuid: '$actor.user.uuid',
},
tran: { $first: '$$ROOT' },
},
},
{
$group: {
_id: {
hour: { $hour: { date: '$tran.time' } },
minute: {
$subtract: [
{ $minute: { date: '$tran.time'} },
{ $mod: [{ $minute: '$tran.time' }, 60] },
],
},
},
count: { $addToSet: '$tran.actor.user.uuid' },
},
},
{
$project: {
start_time: { $add: ['$_id.hour', 0] },
end_time: { $add: ['$_id.hour', 1] },
total_user_arrivals: { $size: '$count' },
_id: 0,
},
},
])

Mongodb aggregation json format by month result

Hello I am working with the reporting api which will going to use in highcharts and I am new to mongodb.
Below is my aggregation query (suggest me modification) :
db.product_sold.aggregate({
$group: {
_id: { year: { $year: "$solddate" }, month: { $month: "$solddate" }, productid: "$productid" },
totalQty: { $sum: "$qty" }
}
})
Output:
{
"_id" : {
"year" : NumberInt(2019),
"month" : NumberInt(2),
"productid" : "11"
},
"totalQty" : 6.0
}
// ----------------------------------------------
{
"_id" : {
"year" : NumberInt(2019),
"month" : NumberInt(2),
"productid" : "14"
},
"totalQty" : 7.0
}
// ----------------------------------------------
{
"_id" : {
"year" : NumberInt(2019),
"month" : NumberInt(1),
"productid" : "13"
},
"totalQty" : 3.0
}
// ----------------------------------------------
{
"_id" : {
"year" : NumberInt(2019),
"month" : NumberInt(2),
"productid" : "10"
},
"totalQty" : 6.0
}
// ----------------------------------------------
{
"_id" : {
"year" : NumberInt(2018),
"month" : NumberInt(2),
"productid" : "12"
},
"totalQty" : 5.0
}
// ----------------------------------------------
{
"_id" : {
"year" : NumberInt(2019),
"month" : NumberInt(2),
"productid" : "15"
},
"totalQty" : 8.0
}
// ----------------------------------------------
{
"_id" : {
"year" : NumberInt(2019),
"month" : NumberInt(1),
"productid" : "11"
},
"totalQty" : 2.0
}
// ----------------------------------------------
What I want in output is something like :
status: 200,
msg: "SUCCESS"
data: [{
1:[
{
"productid": 11,
"totalQty": 3
},
{
"productid": 12,
"totalQty": 27
}
],
2:[
{
"productid": 11,
"totalQty": 64
},
{
"productid": 12,
"totalQty": 10
}
]
}]
For reference attaching the image of the collection
Is there any way to achieve it using aggregation or anything else or I will have to do it manually by code ?
You can append below aggreagation stages to your current pipeline:
db.product_sold.aggregate([
// your current $group stage
{
$group: {
_id: "$_id.month",
docs: { $push: { productid: "$_id.productid", totalQty: "$totalQty" } }
}
},
{
$project: {
_id: 0,
k: { $toString: "$_id" },
v: "$docs"
}
},
{
$group: {
_id: null,
data: { $push: "$$ROOT" }
}
},
{
$project: {
_id: 0,
data: { $arrayToObject: "$data" }
}
}
])
The idea here is that you can use $group with _id set to null to get all the data into single document and then use $arrayToObject to get month number as key and all the aggregates for that month as value.