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
Related
I want to update a MongoDB collection with createddate less than 30 days of current date.
db.transactions.updateMany({ <createdDate lessthan 30 days> }, {$set:{isexpired: true }})
You can use the $lt operator to compare with an absolute date(in this case 1 month ago from now).
eg. =>
db.transactions.updateMany(
{'createddate':{'$lt':ISODate('2022-10-29T18:30:00.000+00:00')}},
{$set:{isexpired: true }}
)
In mongodb,
if I have a date, and I want to query for records that have a date later than the provided date I can do this:
collection.find({datefield:{$gt:somedate}})
And if I want to find records between a date range, I can do an $and with lt and gt.
But say that my datefield is actually datefields, a list of dates. And say that there are the following records for datefield
datefields = [june 1, 2015 hhmmss, june 2, 2015 hhmmss, june 14, 2015 hhmmss]
datefields = [june 1, 2015 hhmmss, june 3, 2015 hhmmss, june 8, 2016 hhmmss, june 17, 2015 hhmmss]
How would I construct the search to fetch for all records whose dates are between say june 3 and june 7, so that I only get the second record. And if ranges are not possible, can I do just a single search for june 3, 2015 while disregarding the hhmmss?
I think this will solve what you're asking. Use an aggregate operation to unwind your arrays and treat each element as a separate value in a document.
db.collection.aggregate( [
{ $unwind : { "$datefields" } },
{ $match : { datefields : { $gt : ISODate("2015-06-02T00:00:01Z"), $lte : ISODate("2015-06-03T23:59:59Z")} } }
])
That alone will give you an "exploded view" of your array results, with one document per array element that matches. If you want to collapse it down you can add a $group stage.
If this isn't what you're asking could you give a bit more detail?
For the second half of your question regarding "disregarding the hhmmss", there are a number of questions already answered on SO about that. Check out Query Mongodb on month, day, year... of a datetime
I'm exporting aggregated data to MS SQL server from mongodb
mongo's $week does not evaluate to the same week as T-SQL datepart(wk, ) or datepart(isowk, ).
Does anyone know how to test the mongodb $week function so I can do some comparisons and see how best to resolve this issue?
Any help would be appreciated.
As far as I can see the differences fall into two main areas, the plain part being described in the documentation:
Weeks begin on Sundays, and week 1 begins with the first Sunday of the year. Days preceding the first Sunday of the year are in week 0. This behavior is the same as the ā%Uā operator to the strftime standard library function.
So the general concept here is that the value returned will be between 0 and 53 inclusive with week 0 being defined as the first week when the days are before Sunday.
So to paraphrase ( because the documentation gets the days wrong ) from the technet source for "datepart":
January 1 of any year defines the starting number for the week datepart, for example: DATEPART (wk, 'Jan 1, xxxx') = 1, where xxxx is any year.
And then (corrected):
The following table lists the return value for week and weekday datepart for '2007-04-21 ' for each SET DATEFIRST argument. January 1 is a Saturday in the year 2007. April 21 is a Saturday in the year 2007. SET DATEFIRST 7, Sunday, is the default for U.S. English.
So where you had documents like this:
{ "date" : ISODate("2007-01-01T00:00:00Z") }
{ "date" : ISODate("2006-12-31T00:00:00Z") }
{ "date" : ISODate("2006-01-01T00:00:00Z") }
The $week operator would return such as this:
{ "date" : ISODate("2007-01-01T00:00:00Z"), "week" : 0 }
{ "date" : ISODate("2006-12-31T00:00:00Z"), "week": 53 }
{ "date" : ISODate("2006-01-01T00:00:00Z"), "week" : 1 }
January 1st in 2006 was a Sunday and is considered the start of week 1, but where it was a Saturday it would be week 0 of 2007. The 31st of December in the previous year is Week 53.
In contrast the DATEPART considers Jan 1st 2007 and Dec 31st 2006 to be in Week 1 as the week ending on the first Sunday of the year. The Sunday is the default US English value but may differ and can in fact be set via SET DATEFIRST
So both have different opinions of where a date belongs in terms of the week of the year, but the general difference will be one with the other consideration days falling at the end of the previous year.
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")}})
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'})