MongoDB query to retrieve distinct documents by date - mongodb

I have documents in the database with a dateTime value like so:
{
"_id" : ObjectId("5a66fa22d29dbd0001521023"),
"exportSuccessful" : true,
"month" : 0,
"week" : 4,
"weekDay" : "Mon",
"dateTime" : ISODate("2018-01-22T09:02:26.525Z"),
"__v" : 0
}
I'd like to:
query the database for a given date and have it return the document that contains the dateTime if the date matches (I don't care about the time). This is mainly to test before inserting a document that there isn't already one for this date. In the above example, if my given date is 2018-01-22 I'd like the document to be returned.
retrieve all documents with a distinct date from the database (again, I don't care about the time portion). If there are two documents with the same date (but different times), just return the first one.
From what I understand Mongo's ISODate type does not allow me to store only a date, it will always have to be a dateTime value. And on my side, I don't have control over what goes in the database.

Try range query with start date time from start of the day to end date time to end of the day. So basically create dates a day apart.
Something like
var start = moment().utc().startOf('day');
var end = moment().utc().endOf('day');
db.collection.find({
dateTime: {
$gte: start,
$lte: end
}
})
Get all distinct dates documents:
db.collection.aggregate(
{"$group":{
"_id":{
"$dateToString":{"format":"%Y-%m-%d","date":"$dateTime"}
},
"first":{
"$first":"$$ROOT"
}
}}])

Related

Converting StringDate to a queryable representation. Group and project sum of today,yesterday, week, month

I was about to try to figure out how to complete the given question.
It might consists of 2 parts, first one being - my collection dates are stored in plain string with a mysql format (YYYY-mm-dd HH:mm:ss), the second how to project the (today, yesterday, 7 day, month - summaries).
I have been experimenting around and this is what I came up with.
Pipe 1.
$match - nothing fancy there just a simple field = value.
Pipe 2.
$addField - trying to process the string date as a ISO date I believe? I am not sure
{
expired: {
$dateFromString: {
dateString: '$expired',
timezone: 'America/New_York'
}
}
}
Pipe 3.
$match - Quoted out wanted to select only a specific range so not more than 30 days - doesn't work
expired: {
$gt: ISODate(new Date(new Date(ISODate().getTime() - 1000*60*60*24*30)))
}
Pipe 4.
$group - Here I group and sum everything per day. So an output is
_id: 2021-09-27, theVal : 100
{
_id: {
$dateToString: {
date: { $toDate: "$expired" },
format: "%Y-%m-%d" }
},
theVal : {$sum:{$first:"$values.quantity"}} // as $values is an array [0].quantity,[1].quantity,[2].quantity - I am just interested in the first element.
}
Pipe 5.
$project - getting rid of the _id field - making it date name field, keeping theVal.
{
"date": "$_id",
"theVal": 1,
"_id": 0
}
theVal is a sum of integers within a day.
Questions
Between Pipe 1 and 2 ( temporary 3 ) I should be able to match dates
within the last 30 days to reduce the processing?
How to get a desired output like this:
{
today : 100,
yesterday : 10,
7days : 220,
month: 1000,
}
Really appreciate any help here.
Tried to "replicate" what you intend to do as you didn't provided sample test data.
You may want to do the followings in an aggregation pipeline:
$match : filter out the ids you want - same as your pipe 1
$dateFromString: use "format": "%Y-%m-%d %H:%M:%S", "timezone": "America/New_York"
$match : filter out records that are within 30 days with $expr and $$NOW
$group : group by date without time; achieved by converting to dateString with date part only
$addFields : project flags that determine if the record are within today, ``yesterday, 7days, month`
$group : As you didn't provided what is the meaning of today, ``yesterday, 7days, month, I made an assumption that they are the cumulative sum in the ranges. Simply and conditional $sum` will do the summation with the help of flags in step 5
Here is a Mongo playground for your reference.

Mongodb query to get document count for each month of a specific year

I have a time field as below in my collection.
"time" : NumberLong(1531958400000)
I first want to query documents by the current year(using $match) and then get the document count for each month.
I have managed to match the year using the below query.
db.myCollection.aggregate([
{$project: {
year: { "$year":{"$add":[new Date(0),"$time"]}}
}
},
{$match: {year: 2021}}
])
How can I write a mongodb query for the mentioned scenario?
Thanks in advance!
You can do following:
parsed the timestamp using $date
compare the parsed date field with current year
$group by $month value to get the count
Here is the Mongo playground for your reference.

How to convert milliseconds to date in MVEL for ElasticSearch

I need to convert a unix_timestamp field to date by MVEL operators.
I have a field which is filled by a mysql imported timestamp. Now I am to get the day date (not datetime) from it and use it in an aggregation.
My Aggregation is like this:
"aggregations" : {
"grouped_item" : {
"terms" : {
"script" : "doc['time_stamp'].value",
"size" : 50
}
}
}
The result of above aggregate is grouped 'by second', but I need 'by date'.
Thanks in advance.
Instead of trying to value script this and use the terms aggregation, use the date histogram aggregation that exists for exactly this purpose.

How to write Mongo query to find video details between two dates

In My mongodb there is a video collection in which there is a creationTime list like following and i want to fetch the record between any two dates by using creationTime.
"creationTime" : {
"logtime" : ISODate("2013-08-12T10:54:44.914Z"),
"logtimeStr" : "12-08-2013 04:24:44",
"day" : 12,
"month" : 8,
"year" : 2013,
"hour" : 16,
"min" : 24,
"second" : 44
}
A little bit nicer way to write a range query, and also just mentioning that $and is implicit within MongoDB and only needs to be used in specific cases that actually require it:
db.collection.find({
"creationTime.logtime": {
"$gt": new Date("2014-08-01"), "$lt" new Date("2014-08-13")
}
})
At least that is the theory for a range query. But currently you have a really big problem and that is your dates are actually being stored as strings.
This is a huge problem as basically when these are strings ( and especially as they are currently formatted ) then you are stuck with a lexical comparison of strings, and the strings you have to not lexically compare properly in the sense of one being "greater" in value than the other.
Strings would need to be presented in the order of "year" then "month" then "day", and with two digit representations in order to match a lexical comparison. What you have currently does not.
But do not change the strings, change them to proper date types and then the query as shown will actually work correctly.
Use Mongodb comparison operators $lt and $gt ( or $lte & $gte for inclusive limits )
How you create START_DATE and END_DATE depends on language you are using .e.g. for javascript you would use new Date()
db.myVideoCollection.find({
'$and':[
{'$creationTime.logtime':{'$gt':START_DATE },
{'$creationTime.logtime':{'$lt':END_DATE }
]
})

MongoDB Aggregation Framework Date NOW

I am attempting to perform a calculation in an aggregation based on the day of the current month. For example, I want to divide the total number of transactions by the day of the month to get transactions per day.
The problem is I can't figure out how to get the current date. I see plenty of examples where it's hardcoded, but what I need is more like the MySQL NOW() function.
I've tried something like this:
> db.statistics.aggregate([{$project: {dayofmonth: {$dayOfMonth: Date()}}}])
{
"errmsg" : "exception: can't convert from BSON type String to Date",
"code" : 16006,
"ok" : 0
}
But that produces the error you see.
How can I get the current day of the current month for use in an aggregation calculation?
You almost did it. You have to write new Date()
db.statistics.aggregate([
{$project: {dayofmonth: {$dayOfMonth: new Date()}}}
])
it will produce results like this:
{
"result" : [
{
"_id" : "statisctiId",
"dayofmonth" : 9
}
}