MongoDb Date query without using range? - mongodb

if i want to find a document created on a specific Day, until now i used a range
from the first minute of the day, to the last minute of the day in seconds , sth like :
query":{"dtCreated":{"$gte":{"sec":1381356782,"usec":0},"$lt":{"sec":1389356782,"usec":0}}}
is is possible to to somehow find all documents where only the Day, Month and year equals "dtCreated" ?
in pseudocode like :
query:{"dtCreated":ISODate("2014-01-23")} <- i know that may not be a valid iso date
but what i want is to find all documents for one day without using lt and gt ?
Sry for bad english and for any hints thanks in advance!

You can do it with the aggregation framework using the date aggregation operators.
Assuming dtCreated is an ISODate field, you could try something like this:
query = [
{
'$project': {
'year': {'$year':'$dtCreated'},
'month': {'$month':'$dtCreated'},
'day':{'$dayOfMonth':'$dtCreated'}
}
},
{
'$match' : {'year':'2014', 'month':'1', day:'1'}
}
]
db.mycollection.aggregate(query)
Edit: as orid rightly remarks, though this is an answer to your question (query for date without using date range), it's not a good way to solve your problem. I would probably do it this way: a range greater than or equal to today, but less than tomorrow
db.foo.find({'dtCreated':{'$gte':ISODate("2014-01-23"), '$lt':ISODate("2014-01-24")}})

Related

Mongodb: Get avg duration of products in inventory

I have a collection with $vehicleId and $Scraped Date. I am trying to get the avg days a car is in inventory. And I want to calculate it for all the historical days.
Sample Doc
{"_id":{"$oid":"5e1b46d853848fae2832e01a"},"Scraped Date":{"$date":{"$numberLong":"1578845911324"}},"vehicleId":{"$numberInt":"1376788"}}
{"_id":{"$oid":"5e1b46d853848fae2832e01b"},"Scraped Date":{"$date":{"$numberLong":"1578845911324"}},"vehicleId":{"$numberInt":"1376771"}}
{"_id":{"$oid":"5e1b46d853848fae2832e01c"},"Scraped Date":{"$date":{"$numberLong":"1578845911324"}},"vehicleId":{"$numberInt":"1376734"}}
{"_id":{"$oid":"5e1b46d853848fae2832e01d"},"Scraped Date":{"$date":{"$numberLong":"1578845911324"}},"vehicleId":{"$numberInt":"1376706"}}
{"_id":{"$oid":"5e1b46d853848fae2832e01e"},"Scraped Date":{"$date":{"$numberLong":"1578845911324"}},"vehicleId":{"$numberInt":"1376505"}}
collection.aggregate([
{'$group': {
'_id' : {'vehicleId': '$vehicleId'},
'date' : {'$addToSet': "$Scraped Date"}
} }
]
)
This code is giving me a list of dates the vehicleId was found in the inventory. How can I convert this to list of dates with avg length the cars were in inventory for that day? I could think of finding the avg length of the dates column but that wont give the me the data day wise.
The current output looks like this in a dataframe:
dataframe view
I figured out a solution. Created a simple for loop for every date and then used the $match query to first filter the results and then calculate the avg length. The question is closed for now. I will update the code in the original question in a while

Find all records older than one year

I have a collection named "listenedMessage" in my MongoDb and it has a field called "timeReceived"
How do I find all records which are older than one year based on the "timeReceived" field?
Based on #Puneet Singh's comment I've came to a solution which retrieves all the records having "timeReceived" field older than a particular month.
function addMonths(date, months) {
date.setMonth(date.getMonth() + months);
return date;
}
db.listenedMessage.find({"timeReceived" : {$lt: addMonths(new Date(), -1)}}).count(); //this will give all the records having timeReceived field older than a month from today

elasticsearch filter dates based on datetime fields

assuming I have the following nested document structure, where my document contains nested routes with an array of date time values.
{
property_1: ...,
routes: [
{
start_id: 1,
end_id: 2,
execution_times: ['2016-08-28T11:11:47+02:00', ...]
}
]
}
Now I could filter my documents that match certain execution_times with something like this.
query: {
filtered: {
query: {
match_all: { }
},
filter: {
nested: {
path: 'routes',
filter: {
bool: {
must: [
{
terms: {
'routes.execution_times': ['2016-08-28T11:11:47+02:00', ...]
}
},
...
]
}
}
}
}
}
}
But what if I would like to filter my documents based on execution dates. What's the best way achieving this?
Should I use a range filter to map my dates to time ranges?
Or is it better to use a script query and do a conversion of the execution_times to dates there?
Or is the best way to change the document structure to contain both, the execution_date and execution_time?
Update
"The dates are not a range but individual dates like [today, day after tomorrow, 4 days from now, 10 days from now]"
Well, this is still a range as a day means 24 hours. So if you store your field as date time, you can use leverage range query : from 20-Nov-2010 00:00:00 TO 20-Nov-2010 23:59:59 with appropriate time zone for a specific day.
If you store it as a String then you will lose all the flexibility of date maths and you would be able to do only exact String matches. You will then have to do all the date manipulations at the client side to find exact matches and ranges.
I suggest play with range queries using Sense plugin and I am sure it will satisfy almost all your requirements.
-----------------------
You should make sure that you use appropriate date-time mapping for your field and use range filter over that field. You don't need to split into 2 separate fields. Date maths will allow you to query just based on date.
This will make your life much easier if you want to do aggregations over date time field.
Reference:
Date Maths:
https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#date-math
Date Mapping : https://www.elastic.co/guide/en/elasticsearch/reference/current/date.html
Date Range Queries:
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html

mongodb indexable $and query possible?

I'm developing an app using a MongoDB database that needs to check for items enabled for today's particular weekday.
Items can be enabled for any individual days of the week. (eg: Monday and Wednesday, or Tuesday and Thursday and Saturday, every day, whatever)
I was going to do this:
var currentWeekDay = Math.pow(2,new Date().getDay());
Therefore
Sunday === 1
Monday === 2
Tuesday === 4
Wednesday === 8
...
Saturday === 64
An example item might be like this
{_id:'blah', weekDays:127}
Now I want to query all items that are enabled for today...
MongoDB has an operator $and, but that's only for logical operations.
It has $bitsAnySet, but it looks like it's only implemented in 3.16.
https://jira.mongodb.org/browse/SERVER-3518
I'm running MongoDB v2.6.10.
So I'm wondering how to come up with a sensible indexable query.
Maybe
{_id:'blah', w0:1, w1:1, w2:1, w3:1, w4:1, w5:1, w6:1} //every day
{_id:'blah', w0:1, w1:0, w2:0, w3:0, w4:0, w5:0, w6:1} //Sat and Sun
That would be easily indexable. Can anyone think of a more terse way of doing it?
One option would be storing days as an array of integers:
{ '_id' : '1' , 'weekDays' : [0,1,2,3,4] } // mon-fri
{ '_id' : '2' , 'weekDays' : [5,6] } // sat-sun
Then you could create a simple index on weekDays field:
db.collection.createIndex({ weekDays : 1 })
And querying would also be pretty simple:
db.collection.find({weekDays : 2}) // wed

Designing a database for querying by dates?

For example, I need to query the last 6 months by the earliest instance for each day (and last day by earliest instances in each hours, and last day by minutes). I was thinking of using MongoDB and having a nested structure like
year:{ month:{ day: { hour: { minute: [array of seconds]
But to get the first instance I would have to sort the array which is costly. Is there an easier way?
Would be better just to have a date field.
And query to be something like:
find(date: {$gt : 'starting_date', $lt : 'ending_date'})