How do I query my documents by specific date and time range? Ie. I want to query documents by specific date range (01-01-2019 - 31-01-2019) and from those dates only the documents which are made in 10am to 12pm.
It would go something like this:
let ref = db.collection('events')
// Query by date range
ref = ref
.where('created', '>=', new Date(2019, 1, 1, 10, 0, 0, 0))
.where('created', '<=', new Date(2019, 1, 1, 12, 0, 0, 0))
// Query by time range in each date
ref = ref
.where('created', '>=', *START TIME = 10pm*)
.where('created', '<=', *END TIME = 12pm*)
So the question is how do I filter hours and minutes every day I queried? Hopefully you understand what I'm asking here! I'll update the question if needed.
Update
Database sturcture is following
/events/{single event document}:
{
cafeId: String,
created: Firestore timestamp // ex. February 2, 2019 at 10:16:00 AM UTC+2
discount: Number,
eventId: Number,
productCount: Number,
keywords: Array,
products: Map,
payment: Map,
returned: Number,
total: Number
}
And when I get this in the client created will transform to:
{ _seconds: Number, _nanoseconds: 0 }
If you want to use "standard" where() methods, you'll probably have to do the second filtering on your front end, from the results received with
ref = ref
.where('created', '>=', new Date(2019, 1, 1, 10, 0, 0, 0))
.where('created', '<=', new Date(2019, 3, 1, 12, 0, 0, 0))
Another approach would be to store, in an extra field (e.g. createdText), your date/time value with a custom format, like for example YYYYMMDDHHMM, with a 24 hours format for the hours (i.e. HH).
This way the document will be correctly sorted and you can query with only one where, as follows:
ref = ref
.where('createdText', '>=', '201902031000')
.where('createdText', '<=', '201902041200')
It is quite common to duplicate the data in an NoSQL database, in particular to allow querying according to your business needs.
Related
I want to get user data of the last 6 months from the current date in MongoDB. I am filtering data by status than getting the array in response. I also want to apply another query on same based on date. I want to filter it once based on last 6 months then in another query based on last 30 days from current date.
My data is -
{
_id: new ObjectId("63ac23187dc7d"),
details: 'hii there i am feeling great today',
status: '1',
createdAt: 2021-11-28T11:06:00.736Z
},
{
_id: new ObjectId("63ac23b357dc96"),
details: 'hi i am feeling good today',
status: '1',
createdAt: 2022-12-28T11:08:40.400Z,
},
{
_id: new ObjectId("63b2b2afa0d8e"),
details: 'Hello!! This is Ankit and feeling good',
status: '1',
createdAt: 2022-11-14T10:31:36.098Z
},
{
_id: new ObjectId("63b2b2sswa0d91"),
details: 'Felling bad a bit',
status: '1',
createdAt: 2023-01-02T10:32:27.149Z
},
{
_id: new ObjectId("63b2b2a0d94"),
details: 'Hmm, its ok ok',
status: '1',
createdAt: 2023-01-02T10:33:19.386Z
}
We use the $gte query operator and JavaScript's Date.now() function to retrieve all order documents with a date greater than or equal to 6 months before the current date. We will use new Date() of JavaScript to get the current date and the setMonth() method to go back 6 months.
You can try this
let sixMonths = new Date();
sixMonths.setMonth(sixMonths.getMonth() - 6);
db.collections.find({ createdAt: { $gte: sixMonths } });
For the days, you can put "1"instead of "6" which is equivalent to 1 month.
consider this mongo collection with following documents and props.
{sku: '3344', frequency: 30, lastProccessedDate: 2021-01-07 15:18:07.576Z},
{sku: '2233', frequency: 30, lastProccessedDate: 2021-02-16 15:18:07.576Z},
{sku: '1122', frequency: 30, lastProccessedDate: 2021-04-13 15:18:07.576Z}
I want to query and get all the documents with (lastProcessedDate + frequency (days)) <= current date.
Essentially in SQL world this is possible to do it, but I can't figure it out to do it in mongo or even if it is possible to do it.
In SQL this would be something like
SELECT * FROM table WHERE DATE_FORMAT(DATE_ADD(FROM_UNIXTIME(lastProcessedDate), INTERVAL frequency DAY), '%Y-%m-%d') <= CURDATE()
If it is not possible I know I can store the calculated date in the document and just query based on that but you know I want to know if it is possible to do it.
Thank you all!
Unfortunately, I can't give you a solution for mongoose. But here is the Mongo query that returns the result you want:
db.getCollection("yourCollection").aggregate([
{
$project: {
_id: 1,
sku: 1,
frequency: 1,
lastProccessedDate: 1,
shiftedDate: {
$add: [
"$lastProccessedDate", { $multiply: [ 24 * 60 * 60 * 1000, "$frequency" ] }
]
}
}
}, {
$match: {
shiftedDate: { $lte: new Date() }
}
}, {
$project: {
_id: 1,
sku: 1,
frequency: 1,
lastProccessedDate: 1,
}
}
])
First, we transform documents to new form that contains the same fields plus a new temporary field - a "shifted" date that is defined as lastProccessedDate + frequency (days) (pay attention that we actually add milliseconds, so there's 24 * 60 * 60 * 1000 in the query). Then we select only that documents which shiftedDate is less than (or equals) current timestamp (new Date() returns current timestamp). Finally, we transform the filtered documents to original form, without the temporary field we used to filter the documents previously.
Perhaps there's a better solution to get documents you want, but this one can resolve your problem too.
So basically, I have an array of date between a range:
['2019-01-01, '2019-01-02', '2019-01-03'...'2019-01-30'];
And an array of objects containing data for the dates in the above range:
[{date: '2019-01-01', count: 2'}, {date: '2019-01-05', count: 4'}...{date: '2019-01-25', count: 3}]
Note, if there is no count at a particular date between those ranges in the first array, it does not appear in the second array at all. So, if there were 30 dates in the first array, there may only be 25 dates in the second array.
Ultimately, I would like to build an array of object in the form:
[
{ date: '2019-01-01',
count: 2
},
{
date: '2019-01-02',
count: 0
},
];
So, the array will contain an object for each date in the range (from first array), and will get the count (from the second array). If the date is not in the second array, then it will set the count as 0 in the array of objects.
I'm having a really hard time trying to figure out how to do this. I've tried various loops but am getting nowhere. Can anyone point me in the right direction?
Create a new array with same value number as range.
For each value of range, check in counts if there is already an existing count.
If there's one, return it. If there's none, return a new "0 count".
Code version:
const range = [
'2019-01-01',
'2019-01-02',
'2019-01-03',
'2019-01-04',
'2019-01-05',
'2019-01-06',
'2019-01-07',
];
const counts = [
{date: '2019-01-01', count: 2},
{date: '2019-01-05', count: 4},
{date: '2019-01-07', count: 3},
];
const result = range.map(date =>
counts.find(element => element.date === date) || { date, count: 0 });
console.log(result);
So I am having this problem with Javascript and JSON data.
When I fetch data from a certain URL I get the data in a JSON file with strings.
Now my problem is. One of these strings is a date which I need to use so when the date is less than current date, that it will form a new string out of it so I can properly display data to HTML I am designing. ?
Idea of my project is that it displays events listed for that day and I want to display only upcoming events, not the ones that already ended.
Note The date is in ISO_8601 format. Also I am new to scripting. Thank you in advance.
I dont't know how your data look like, but generally speaking, you need to perform two steps:
convert strings into actual Date objects
filter out past dates
Converting is pretty easy, just new Date(<ISO 8601 string>):
new Date("2018-06-12"); // -> Tue Jun 12 2018 01:00:00 GMT+0100
new Date("2018-07-13"); // -> Fri Jul 13 2018 01:00:00 GMT+0100
Filtering out the past events can be done with Array.filter. You give it a function that returns True or False, and it runs it for each array item. Items for which the functiuon returned True are put into a new array:
[1, 3, 4, 6, 7].filter(number => number > 4); // -> [6, 7]
[1, 3, 4, 6, 7].filter(number => number <= 4); // -> [1, 3, 4]
So, to filter past dates/times, you just compare them to today's date. The only tricky thing is that giving a string like 2018-06-07 (date only, without time specified) to new Date(…) sets the time to the current one:
new Date("2018-06-07"); // -> Thu Jun 07 2018 01:00:00 GMT+0100
If you need to compare only by days, not hours or even minutes, it's handy to set the time to past midnight:
(new Date("2018-06-07")).setHours(0) // -> Thu Jun 07 2018 00:00:00 GMT+0100
So, when put together:
const data = {
events: [
{ name: "Event 1", date: "2018-06-12" },
{ name: "Event 2", date: "2018-07-10" },
{ name: "Event 3", date: "2018-07-12" },
{ name: "Event 4", date: "2018-07-13" },
{ name: "Event 5", date: "2018-08-01" }
]
}
const today = (new Date()).setHours(0) // past midnight
const todayAndFutureEvents = data.events.filter(event => (new Date(event.date)) >= today);
console.log(todayAndFutureEvents);
Another problem could arise if your events happen across multiple timezones, but that's probably out of scope of this question…
As Simeon said my opinion is same, I would like to add little bit more information with him.
When you got the dates you need to do two things,
First is checking if it is a valid date
Its upcoming/future date or not.
You haven't added the example dates JSON in question, I am assuming you have a JSON like below.
[
{name: "Something", date: "12-12-2018"},
{name: "Something", date: "12-12-2017"},
{name: "Something", date: "12-12-2019"},
{name: "Something", date: "12-5-2018"},
{name: "Something", date: "12-2-2018"},
{name: "Something", date: "SOMETHING_INVALID"},
{name: "Something", date: "12-12-2016"},
]
You can filter the valid date and future dates with a filter like this,
let dates = [
{name: "Something", date: "1-12-2018"},
{name: "Something", date: "2-12-2017"},
{name: "Something", date: "3-12-2019"},
{name: "Something", date: "4-5-2018"},
{name: "Something", date: "5-2-2018"},
{name: "Something", date: "InvalidSomething"},
{name: "Something", date: "7-12-2016"},
]
let filteredDates = dates.filter((item) => {
let date = new Date(item.date);
if(date !== 'Invalid Date' && Date.now() < date.getTime()){
return item;
}
});
console.log(filteredDates);
Little clarification:
Date.now() and date.getTime() both are used to get the timestamp and I am comparing inside JavaScript Filter, if the date object not returning "Invalid Date" string and if the **timestamp number is bigger than today's timestamp then it's future date.
When those two condition matched then the filter it will return the whole object which is being collected by filteredDates variable. when the loop is done you will get your array for further use. Cheers!
If you pass that string to a new Date(yourString) function it will give you back a JavaScript date object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
Example:
const newDate = new Date('2008-09-15T15:53:00')
// Will return a date object with the value of:
// Mon Sep 15 2008 15:53:00 GMT-0700 (Pacific Daylight Time)
const currentDate = Date.now();
// Will return a date object with the current date.
console.log(newDate < currentDate);
// Will compare the two dates.
Well, you're not really providing enough information about your JSON structure and what you have already achieved, so please add more details if this isn't enough, but something like this, I'm guessing:
var eventsFromMyJSONstring = JSON.parse(theJSONstringFetchedFromCertainURL);
var currentDate = new Date();
eventsFromMyJSONstring.forEach(function(iEvent) {
iEvent.newVarAsDate = new Date(iEvent.textDate);
if (iEvent.newVarAsDate >= currentDate) {
alert('hey, this object is from today or future');
}
});
edit: also, maybe you want to use filter to get just the current and future events... something like:
var currentAndFutureEvents = eventsFromMyJSONstring.filter((iEvent) => new Date(iEvent.textDate) >= new Date());
(ES6 assumed there...)
I am implementing Fullcalendar in my project but i'm stuck in between, what i want is just opposite of business hours for example
in business hours
businessHours:
{
dow: [0, 1, 2, 3, 4, 5, 6, 7 ],
start: '08:00',
end: '09:00' ,
},
when i give this code, then in fullcalendar it beacome like this
it means it show grey field for all hours but 8-9
i want to give a feature where a user can give his time break and then in calendar it will some other color on the particular day and time.
also i thought to fetch the time from db and show as a breakTime but the problem is i can only fetch time and day not date so how can i show in event with only day and time?
any idea how can i achieve it.
I got the answer, for those who want the exact feature just add this code in fullcalendar.js
function F(e) {
var i, r = n.businessHours,
s = {
className: "fc-nonbusiness",
start: "09:00",
end: "17:00",
dow: [1, 2, 3, 4, 5],
rendering: "background"
},
o = I.getView();
return r && (i = t.extend({}, s, "object" == typeof r ? r : {})), i ? (e && (i.start = null, i.end = null), T(E(i), o.start, o.end)) : []
}
and then you can show you breaktime using business hours cheers..!
Providing you have FullCalendar 2.9.1 or later, you can give multiple businessHours definitions. Therefore you can express the day as two (or more) periods of working time, with the break shown in grey in between them. It won't be in a different colour entirely, but it will at least be clear what the working hours are. For example:
businessHours: [
{
dow: [1, 2, 3, 4, 5], // Monday - Friday
start: '09:00',
end: '12:30'
},
{
dow:[1, 2, 3, 4, 5],
start: '13:30',
end: '17:00'
}
]
would imply a one-hour break between 12:30 and 13:30
If you prefer to fetch the time from the DB, I would first ask - what is to stop you adding the date yourself in order to create an event? You can do it either on the server or in the client, it's up to you.