I have write below the code.I try to split date and time but I can't get correct solution. I write the service in Node JS. If i try get date between dates, It is working. But if i try to fetch exact date, it is not working.
exports.screenLog = function(req,res){
console.log(req.query);
Timesheet.find({userId: req.params.id,startTime: $match:{$gte : new Date(req.query.startTime),$lte: new Date(req.query.endTime)}}, function (err, timesheet) {
console.log(timesheet);
var timesheetIdArray = timesheet.map(function(ele){return ele._id});
Screenshot.find()
.where('timesheetId')
.in(timesheetIdArray)
.exec(function(err,data){
//console.log('ScreenData:',data);
if(err) {
res.send(err);
}
res.send(data);
});
});
This is My input format below:
[
{
"_id": "5963653e6b43611240189ea2",
"timesheetId": "595f4f2ec456a422bc291169",
"imageUrl": "/images/2017-07-10_05_00_06_PM.jpg",
"__v": 0,
"createdTime": "2017-07-07T09:06:54.000Z"
},
{
"_id": "5964bef37302792b0864009e",
"timesheetId": "595f4f2ec456a422bc291169",
"imageUrl": "/images/2017-07-11_05_35_07_PM.jpg",
"__v": 0,
"createdTime": "2017-07-11T12:05:07.687Z"
},
{
"_id": "5964bf897302792b086400ad",
"timesheetId": "595f4f2ec456a422bc291169",
"imageUrl": "/images/2017-07-11_05_37_37_PM.jpg",
"__v": 0,
"createdTime": "2017-07-11T12:07:37.446Z"
},
{
"_id": "5964ddf0ee77e90288d26eec",
"timesheetId": "5964ddf0ee77e90288d26eeb",
"imageUrl": "/images/2017-07-11_07_47_20_PM.jpg",
"__v": 0,
"createdTime": "2017-07-11T14:17:20.651Z"
}]
Date and Time Can't be Split in MongoDB.They are Store in Date object in database.
But You can Compare the dates By $gte,$lte,$eq etc.
For the Comparisons you can Only Compare with UTC date ,For this You can find out moment Library
eg : date:{ $gte : moment(YOUR_DATE_IN_STRING) }
I am not too familiar with Node.Js, but I think the project aggregation may help you out here:
db.MyCollection.aggregate(
[
{
$project:
{
year: { $year: "$MyDateField" },
month: { $month: "$MyDateField" },
day: { $dayOfMonth: "$MyDateField" },
hour: { $hour: "$MyDateField" },
minutes: { $minute: "$MyDateField" },
seconds: { $second: "$MyDateField" },
milliseconds: { $millisecond: "$MyDateField" },
dayOfYear: { $dayOfYear: "$MyDateField" },
dayOfWeek: { $dayOfWeek: "$MyDateField" },
week: { $week: "$MyDateField" }
}
}
]
)
That will return this:
{
"_id" : "5897697667f26827dc9c9028",
"year" : 2017,
"month" : 2,
"day" : 5,
"hour" : 18,
"minutes" : 5,
"seconds" : 41,
"milliseconds" : 822,
"dayOfYear" : 36,
"dayOfWeek" : 1,
"week" : 6
}
Is that getting you any closer to a solution?
You can do smth like this in mongo shell:
db.foo_collection.aggregate([
{'$addFields': {
'extracted_date': {'$dateFromParts': {
'year': {'$year': "$some_datetime_field"},
'month': {'$month': "$some_datetime_field"},
'day': {'$dayOfMonth': "$some_datetime_field"}
}}
}},
{'$match': {'$extracted_date': ...}}
])
This query extracts date from datetime field and then applies some filter expression on this date.
Related
I'am developing an api in nodejs.
I have the document in follwing stucture:
{
"_id" : ObjectId("5ecd26504df3372a38afffd9"),
"balance" : 104000,
"bankID" : "Bank-1",
"userEmail" : "kumarshreyas073#gmail.com",
"bankName" : "Corporation Bank",
"accountNumber" : "03214569874563",
"ifsCode" : "CORP0001236",
"branch" : "Udupi",
"address" : "Udupi",
"city" : "Udupi",
"state" : "Karnataka",
"openingBalance" : 100000,
"transactions" : [
{
"credit" : 2000,
"debit" : 0,
"_id" : ObjectId("5ecd26614df3372a38afffea"),
"transactionID" : "CashTransaction-5ecd26614df3372a38afffe8",
"date" : "30-05-2026",
"particulars" : "By Cash-1",
"voucherType" : "Cash"
},
{
"credit" : 0,
"debit" : 2000,
"_id" : ObjectId("5ecd272d4df3372a38b00012"),
"transactionID" : "Receipt-5ecd272d4df3372a38b00009",
"date" : "29-07-2020",
"particulars" : "To Suresh kumar",
"voucherType" : "Receipt"
},
{
"credit" : 0,
"debit" : 2000,
"_id" : ObjectId("5ecd272d4df3372a38b00014"),
"transactionID" : "Receipt-5ecd272d4df3372a38b00003",
"date" : "30-05-2024",
"particulars" : "To Karthik",
"voucherType" : "Receipt"
}
],
"idCounter" : 1,
"__v" : 0
}
I need to extract only those transactions between from date = "20/07/2020" and to date = "31/07/2020".
The code I written is as follows:
exports.trail_balance = async (req, res, next) => {
var trailBalance = {
userEmail: req.body.userEmail,
fromDate: req.body.fromDate,
toDate: req.body.toDate,
};
var bankAccount = await Bank.aggregate([
{ $match: { userEmail: req.body.userEmail } },
{
$addFields: {
transactions: {
$filter: {
input: "$transactions",
as: "transactions",
cond: {
$and: [
{
$gte: ["$$transactions.date", trailBalance.fromDate],
},
{
$lte: ["$$transactions.date", trailBalance.toDate],
},
],
},
},
},
},
},
]);
res.status(200).json({
result: 1,
bankAccount: bankAccount.length > 0 ? bankAccount : [],
});
};
Actual result I expect is:
{
"result": 1,
"bankAccount": [
{
"_id": "5ecd26504df3372a38afffd9",
"balance": 104000,
"bankID": "Bank-1",
"userEmail": "kumarshreyas073#gmail.com",
"bankName": "Corporation Bank",
"accountNumber": "03214569874563",
"ifsCode": "CORP0001236",
"branch": "Udupi",
"address": "Udupi",
"city": "Udupi",
"state": "Karnataka",
"openingBalance": 100000,
"transactions": [
{
"credit" : 0,
"debit" : 2000,
"_id" : ObjectId("5ecd272d4df3372a38b00012"),
"transactionID" : "Receipt-5ecd272d4df3372a38b00009",
"date" : "29-07-2020",
"particulars" : "To Suresh kumar",
"voucherType" : "Receipt"
}
],
"idCounter": 1,
"__v": 0
}
But, I'am getting all transactions.
I even tried passing date in, from date = "20-07-2020" and to date = "31-07-2020". This too returns all transaction.
All the date stored in DB are of type String.
The problem is your date format. As you have started your date with day in your saved data in database and type of date is string, so in comparison to your query, it always start with day and it's incorrect. because in date comparison, at first years must be compared, then months and lastly, day. But you are doing it in wrong way.
In this scenario, mongodb is doing write! because in your from date, 2 is less or equal to 2 and 3 and in your to date, 3 is greater or equal to 2 and 3. So its doing well.
I changed your saved data date format to yyyy-mm-dd and your query was correct.
If changing data is not possible for you, you can also change data in a pipeline stage of your aggregate query. Use the link below:
https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromString/
You are almost there. The problem is with your data. It has invalid date format.
mongo playground
I changed to proper date format for one of the transactions as below
"date": ISODate("2026-05-30"),
mongo date format
So if you have proper format, then the query will work.
new Date("<YYYY-mm-dd>") returns the ISODate with the specified date.
new Date("<YYYY-mm-ddTHH:MM:ss>") specifies the datetime in the client’s local timezone and returns the ISODate with the specified datetime in UTC.
new Date("<YYYY-mm-ddTHH:MM:ssZ>") specifies the datetime in UTC and returns the ISODate with the specified datetime in UTC.
new Date(<integer>) specifies the datetime as milliseconds since the Unix epoch (Jan 1, 1970), and returns the resulting ISODate instance.
Suggesting few fixes,
convert your string date to ISO date using new Date("2020-07-31"),
var trailBalance = {
userEmail: req.body.userEmail,
fromDate: new Date(req.body.fromDate),
toDate: new Date(req.body.toDate),
};
convert collection's field transactions.date string to ISO date using $dateFromString
format: %d-%m-%Y should match exact format of date in transactions.date
{
$dateFromString: {
dateString: "$$transactions.date",
format: "%d-%m-%Y"
}
}
Look at the Working Playground: https://mongoplayground.net/p/-KWgRCSwD8h
Your final query,
var bankAccount = await Bank.aggregate([
{
$match: {
userEmail: trailBalance.userEmail
}
},
{
$addFields: {
transactions: {
$filter: {
input: "$transactions",
as: "transactions",
cond: {
$and: [
{
$gte: [
{
$dateFromString: {
dateString: "$$transactions.date",
format: "%d-%m-%Y"
}
},
trailBalance.fromDate
]
},
{
$lte: [
{
$dateFromString: {
dateString: "$$transactions.date",
format: "%d-%m-%Y"
}
},
trailBalance.toDate
]
}
]
}
}
}
}
}
]);
My mongodb aggregation query should return daily, weekly, monthly, yearly data within specific date ranges.
Example: let's assume dates between 1st Feb to 1st March.
the data for daily should be: 1st, 2nd, 3rd..
Weekly period will be: 1st Feb, 8th Feb, 15th Feb, 22nd Feb ..
monthly period will be 1st Feb, 1st march ..
Look at example below:
Let's say my API accepts: startDate, endDate, interval as body params.
req.body will be something like this:
{
startDate: "",
endDate: "",
platform: "",
interval: "daily" // could be "weekly", "monthly", "yearly"
}
These params will be passed to my model where I have some aggregation code which will be mentioned below:
MessagesSchema.statics.totalMessages = ( startDate, endDate, platform, interval ) => {
return Messages.aggregate([{
$match: {
platform: platform,
timestamp: {
$gte: new Date(startDate),
$lte: new Date(endDate)
}
}
},
{
$project: {
timestamp: {
$dateToString: {
format: '%Y-%m-%d',
date: '$timestamp'
}
}
}
},
{
$group: {
_id: {
timestamp: '$timestamp'
},
count: {
$sum: 1
}
}
},
{
$sort: {
'_id.timestamp': 1
}
}
]).exec();
Let's assume Weekly data from 1st Feb 2019 - 1st March 2019;
expected result:
[
{
"_id": {
"timestamp": "2019-02-01"
},
"count": 2
},
{
"_id": {
"timestamp": "2019-02-08"
},
"count": 2
},
{
"_id": {
"timestamp": "2019-02-15"
},
"count": 2
}
]
actual result:
[
{
"_id": {
"timestamp": "2019-02-01"
},
"count": 2
},
{
"_id": {
"timestamp": "2019-03-02"
},
"count": 2
},
{
"_id": {
"timestamp": "2019-03-02"
},
"count": 2
}
]
I need to get the count of individual users for a particular date range that too on each day basis. Let's say, there are a total of 100 users within a month (1st - 30th), I need to get the count like
{
1st - 2 users
2nd - 10 users
}
MessagesSchema.statics.totalMessagesGraph = (id, startDate, endDate, platform) => {
return Messages.aggregate([
{
$match: {
id: id,
platform: platform,
timestamp: {
$gte: new Date(startDate),
$lte: new Date(endDate)
}
}
}
])
}
What should be here to get the desired result ?
Expected Result:
For that particular date ranges the count for each day.
{
date1 - 20,
date2 - 22,
date3 - 24,
...
date30 - 12
}
The expected output should look like above. What query should be proceeded after $match. If possible please take a sample dataset and provide the output.
Use $group to get day wise count
for example
db.collection.aggregate([
{
$match: {
//id: id,
//platform: platform,
//timestamp: {
//$gte: new Date(startDate),
//$lte: new Date(endDate)
//}
//}
// Your matching logic
},
/* Now grouping users based on _id or id parameter for each day
from the above match results.
$createdAt can be replaced by date property present in your database.
*/
{ $group : {
id : { day: { $dayOfMonth: "$createdAt" },
month: { $month: "$createdAt" },
year: { $year: "$createdAt" } },
count : {$sum : 1}
}
}
])
Based on this you will get output like :
{
"_id" : {
"day" : 14,
"month" : 1,
"year" : 2017
},
"count" : 2.0
}
/* 2 */
{
"_id" : {
"day" : 31,
"month" : 1,
"year" : 2017
},
"count" : 8.0
}
/* 3 */
{
"_id" : {
"day" : 2,
"month" : 1,
"year" : 2017
},
"count" : 4.0
}
...
You can use the above query results to get required output.
More precisely you can remove month and year parameters from group query to get output like :
/* 1 */
{
"_id" : {
"day" : 25
},
"count" : 7.0
}
/* 2 */
{
"_id" : {
"day" : 18
},
"count" : 4.0
}
/* 3 */
{
"_id" : {
"day" : 17
},
"count" : 4.0
}
...
For reference you can check the mongoDB documentation also refer this.
MongoDB Aggregation Queries for "Counts Per Day"
Hope above example help you in getting the required output.
Here is the solution which I figured out after few trials.
{
'$project': {
timestamp: {'$dateToString': {format: '%Y-%m-%d', date: '$timestamp'}} }
}, {
'$group': {
_id: {timestamp: '$timestamp'},
count: {'$sum': 1}
}
}
And here is the output
"response": [
{
"_id": {
"timestamp": "2019-01-08"
},
"count": 1
},
{
"_id": {
"timestamp": "2019-01-13"
},
"count": 1
},
{
"_id": {
"timestamp": "2019-01-16"
},
"count": 1
},
{
"_id": {
"timestamp": "2019-01-17"
},
"count": 1
},
{
"_id": {
"timestamp": "2019-01-19"
},
"count": 1
},
{
"_id": {
"timestamp": "2019-02-01"
},
"count": 1
}
]
i am getting data using nodejs with MongoDB. I have objects in the MongoDB. and now I am going for the getting data using date wise and my datetime filed is a timestamp. and I want to get data from start date to end date using MongoDB.
must imp note i want to print date in the my expected op.
here I this is my objects =>
{
"_id" : ObjectId("595be16ee04602135828e25c"),
"Action" : "Comment",
"datetime" : 1507099928000 // 4th oct 2017 convert date just for info here write
},
{
"_id" : ObjectId("595be16ee04602135828e25c"),
"Action" : "Comment",
"datetime" : 1508139441716 // 16th oct 2017 convert date just for info here write
}
{
"_id" : ObjectId("595be16ee04602135828e25c"),
"Action" : "Comment",
"datetime" : 1508139441716 // 16th oct 2017 convert date just for info here write
}
{
"_id" : ObjectId("595be16ee04602135828e25c"),
"Action" : "Like",
"datetime" : 1508139441716 // 16th oct 2017 convert date just for info here write
},
this is my query =>
InstaAc.aggregate([
{
"$match": {
"_id": ObjectId("595be16ee04602135828e25c"),
"datetime": {
"$lte": 1508141028150, "$gte": 1507622568000
}
},
"Action": {
$in: ["Comment", "Like"]
}
},
{
"$addFields": {
"datetime": {
"$add": [new Date(0), "$datetime"]
}
}
},
{
"$group": {
"_id": {
"$dateToString": {
"format": "%d-%m-%Y",
"date": "datetime"
}
},
"commentcount": { $sum: { $cond: [{ $eq: ["Action", "Comment"] }, 1, 0] } },
"likecount": { $sum: { $cond: [{ $eq: ["Action", "Like"] }, 1, 0] } },
}
},
{
"$sort": {
"_id": 1
}
}
]).exec(function (err, data) {
if (err) {
console.log(err);
}
else {
console.log(data);
}
})
this is my query above and I am getting an error like this "date is not defined"
please, anyone, know how can fix this then please help me.
my excepted o/p =>
{ _id: '16-10-2017', commentcount: 2 ,likecount:1},
Before you run your query create a date object and use that object instead of new Date(0).
var myDate = new Date(0);
And in your query
"$addFields": {
"datetime": {
"$add": [myDate, "$datetime"]
}
I am having this aggregation pipeline code below that I would like to run for every day of the year! Essentially calculating the minimum, maximum and average temperature ("TEMP" field) for every day of the year. At the moment I am calling this piece of code 365 times, passing the start date and the end date of a day.
Obviously this is very inefficient. Is there any way to loop this within mongo so that its faster, and return an array of 365 average values, 365 min values and 365 max values or something like that. Im using a timezone library to derive the start date and end date.
collection.aggregate([
{
$match:{$and:[
{"UID" : uid},
{"TEMP" :{$exists:true}}
{"site" : "SITE123"},
{"updatedAt": {$gte : new Date(START_DATE_ARG), $lte : new Date(END_DATE_ARG)} }
]}
},
{ "$group": {
"_id": "$UID",
"avg": { $avg: $TEMP },
"min": { $min: $TEMP },
"max": { $max: $TEMP }
}
}
], function(err, result){
if (err){
cb(1, err);
}
else{
cb(0, result);
}
});
});
The datasets look like this
....
{UID: "123", TEMP: 11, site: "SITE123", updatedAt: ISODate("2014-09-12T21:55:19.326Z")}
{UID: "123", TEMP: 10, site: "SITE123", updatedAt: ISODate("2014-09-12T21:55:20.491Z")}
....
Any ideas? Maybe we can pass all the timestamps of all the days of the year in the aggregation pipeline?
Thank you!!
Why run this for every day when you can simply make the date part of the grouping key? This is what the date aggregation operators exist for, so you can aggregate by time frames in a whole period at once without looping:
collection.aggregate([
{ "$match":{
"UID": uid,
"TEMP":{ "$exists": true }
"site" : "SITE123",
"updatedAt": {
"$gte": new Date(START_DATE_ARG),
"$lte": new Date(END_DATE_ARG)
}}
}},
{ "$group": {
"_id": {
"uid": "$UID",
"year": { "$year": "$updatedAt" },
"month": { "$month": "$updatedAt" },
"day": { "$dayOfMonth" }
},
"avg": { "$avg": "$TEMP" },
"min": { "$min": "$TEMP" },
"max": { "$max": "$TEMP" }
}}
])
Or possibly just condensing the date to a timestamp value instead. A little trick of date math with date objects:
collection.aggregate([
{ "$match":{
"UID": uid,
"TEMP":{ "$exists": true }
"site" : "SITE123",
"updatedAt": {
"$gte": new Date(START_DATE_ARG),
"$lte": new Date(END_DATE_ARG)
}}
}},
{ "$group": {
"_id": {
"uid": "$UID",
"date": {
"$subtract": [
{ "$subtract": [ "$updatedAt", new Date("1970-01-01") ] },
{ "$mod": [
{ "$subtract": [ "$updatedAt", new Date("1970-01-01") ] },
1000 * 60 * 60 * 24
]}
]
}
},
"avg": { "$avg": "$TEMP" },
"min": { "$min": "$TEMP" },
"max": { "$max": "$TEMP" }
}}
])
Of course your "date range" here is now all of the dates you require to be in the results, so the start and the end dates for all the things where you intended to loop. The grouping is done in either case to reflect "one day", but of course you could change that to any interval you want to.
Also note that your use of $and here is not necessary. Queries in MongoDB "and" conditions by default. The only time you need that operator is for multiple conditions on the same field that would otherwise not be valid JSON/BSON.