How do I query document where datetime == datetime in Firestore - node.js

I have a problem try to query a document using DateTime object
document in path /users/{userId}/payments/{paymentDoc}
which I have document structure like this
Document data: {
banking: '',
isPaid: false,
endDate: Timestamp { _seconds: 1592179200, _nanoseconds: 0 },
startDate: Timestamp { _seconds: 1590969600, _nanoseconds: 0 }, **June 1, 2020 at 7:00:00 AM UTC+7**
totalIncome: 100
}
where I try to query document is
firstDayOfMonth = new Date(2020, 05, 01) **maybe wrong here?**
userPaymentRef = db.collection('users')
.doc(userId)
.collection('payments')
.where('startDate', '==', firstDayOfMonth)
.get()
.then(function (doc) {
if (doc.exists) {
console.log("Document data:", doc.data());
return true;
} else {
console.log("No such document!");
return false;
}
}).catch(function (error) {
console.log("Error getting document:", error);
});
But in firebase functions log its said No such document!
I try to log the timestamp of startDate I stored and timestamp of date I want to query. It's the same, but it's said 'No such document' is my query is wrong? or DateTime I want to query is wrong?
Edit:
Functions log
the timestamp of document I store and the timestamp from DateTime is matched but can't find document

If you have a timestamp field field in a document, it can only be matched exactly by other Date or Timestamp objects. The precision down to the nanosecond must match. Two timestamps with the same day but different times of the day are not equal.
Also bear in mind that the timestamp objects don't encode a timezone - they always use UTC. If you use a Date object, it must be created with the exact same moment in time as the timestamp in order to get an equality match. Date objects that don't specify precise moment in time will use the local computer's timestamp, which is definitely not guaranteed to match the time of day on any other computer.
The bottom line is this: if you want two timestamps to be equal, they must both represent the exact same moment in time, measured to the nanosecond.

Related

How to query a table on timestamp with Sequelize ORM

I would like to query my Table for the value at midnight (00:00:00) everyday.
So The system gets a value every minutes but I want the value at 00:00:00 so I can plot daily sales.
Here is how my code looking so far:
const data = await Chart.findAll({
where: {
DATEPART(hour, TimeStamp): 0,
DATEPART(minute, TimeStamp): 0
},
});
res.send(data);
};
TimeStamp is the name of the field on SQL table that contain the time stamp.

Type casting in prisma

I have one doubt on the prisma query, how can I do type casting in the prisma query,
In my case, I need to perform where query against the datetime values, Here the input will be either one of the strings or a timestamp. if the input is a timestamp value, then it works fine, if the value is not a timestamp value, then the prisma throws an error.
return this.DB.$transaction([
this.User.findMany({
take,
skip,
where: {
created_at:{ equals: '2022-10-03T05:24:04.712Z'}
}
}),
this.User.count({
where: { ...queries, ...columnQuery }
})
])
In the above case, the query works fine, if I provide the string instead of the timestamp it throw an error
return this.DB.$transaction([
this.User.findMany({
take,
skip,
where: {
created_at:{equals: '12'}
}
}),
this.User.count({
where: { ...queries, ...columnQuery }
})
])
Here the order by input is 12, if the value is not a time stamp type, I also need to perform the where query. In my understaing, if we perform the typecasting to string against created_at column, we can perform filter query in typestamp datatype column, even though the input is not a timestamp type
friends can you help me to fix this ?

Timezone problems with MongoDB and NodeJs

So the problem I'm currently having is :
I've a list of gym classes, which every class has an OpeningTime. I want to fetch all the classes from the current day, but. I'm not getting the same result locally and in production, cause for some reason, when Im deploying my backend to Heroku, the timezone is being setted by default to UTC (when I've a GMT-3 timezone).
Here is my query :
var now = moment();
var startOfDay = now.startOf('day').format();
var endOfDay = now.endOf('day').format();
var clasesDB = await Clase.find({ $and: [{ openingTime: { $gte: startOfDay } }, { openingTime: { $lte: endOfDay } }] })
So, like I said before, the problem is ocurring when, for example:
When I fetch the classes at my local time (Ex: 02-26-19 21:00hs ( GMT-3) ), the queries are actually showing the classes from 02-27, because, at MINE 21:00hs, on the server side is already 00:00, so, the date is not 02-26 anymore. And I dont want this kind of output.
How can I get a workaround to solve this?
Thanks in advance! :)
Don't use .format(), this makes a string. Compare directly Date values, i.e. use
var now = moment();
var startOfDay = now.startOf('day').toDate();
var endOfDay = now.endOf('day').toDate();
By default moment uses local times, so moment().startOf('day') returns midnight of local time. If you want to get midnight of UTC then use moment.utc().startOf('day').
If you don't rely on "local" time zone, then you can specify it like moment.tz("America/New_York").startOf('day')
No matter which time you need, never compare Date values by string, use always actual Date value.
By default in MongoDB a date field is stored in UTC, You can create a date with offset while writing to store it in your timeZone. But you've not done it while writing documents then you need to convert date field to your required timeZone while reading data from database. Check this below example.
JavaScript Code :
const today = new Date().toLocaleDateString(undefined, {
day: '2-digit',
month: '2-digit',
year: 'numeric'
}) // 02/26/2020. If your Heroic server is in different location then specify your locale in place of undefined - whereas undefined picks local time by default. Ex:- 'en-Us' for USA
Query :
db.collection.aggregate([
{ $addFields: { timewithOffsetNY: { $dateToString: { format: "%m/%d/%Y", date: "$openingTime", timezone: "America/New_York" } } } },
{ $match: { timewithOffsetNY: today } }, { $project: { timewithOffsetNY: 0 } }
])
Above query is written for New York timeZone, you can convert it according to your timeZone, In test url you can see 1st doc is not returned though it is on 2020-02-26 cause offset to New York as of today is 5hrs, So after converting date becomes as 2020-02-25.
Test : MongoDB-Playground
Ref : $dateToString

Mongoose: Running Scheduled Job Query by Date

I want to create a scheduled job for patients in a hospital. The patients will be informed every month by their reg_date.
I'm using new Date().getDate() inside my scheduled Jobs to run at 8.00 AM in the morning to send SMS to my patients. Meanwhile, I had been using string format date to save reg_date in my mongoDB. Here is snippets of my mongoDB docs :
{
customer: "John",
reg_date: "2017-02-17T16:39:26.969Z"
}
I've ben surfing for solutions but it turns out nothing, so I decided to post myself. Here is what i am trying to do :
customer.find({"reg_date.getDate()" : new Date(2017, 03, 17).getDate()})
.then(function(data) {
for (var key in data.length) {
sendTheSMS(key[data]);
};
});
E.g: What I am doing is "I want to get every patient who register at 17th day of the month and send them a SMS".
Any help will be appreciated. :D
For this type of bit complex query you need to use aggregation method instead regular find method.
$project this will help you to project your fields, here we are creating a new temporary field day with only date of the reg_date. Then we query using the new field day and we get the result.
This temp field day will never added to your schema or model, it is just like temp view we are creating like in SQL.
Here i projected only customer and day but Please project all the fields necessary in the result.
function getCustomerList(day, callback){
customer.aggregate([
{
$project:{
"customer": "$customer", //repeat the same for all field you want in result
"reg_date": "$reg_date",
"day":{$dayOfMonth:"$reg_date"} //put day of month in 'day'
}
},
{
$match:{
"day": day //now match the day with the incoming day value
}
},
], function(err, result){
callback(err, result);
})
}
getCustomerList(17, function(err, result){ // call the function like this with date you want
// Process the err & result here
});
Result will be like this
[{
"_id" : ObjectId("571f2da8ca97eb10163e6e17"),
"customer" : "John",
"reg_date" : ISODate("2016-04-17T08:58:16.414Z"),
"day" : 17
},
{
"_id" : ObjectId("571f2da8ca97eb10163e6e17"),
"customer" : "Prasanth",
"reg_date" : ISODate("2016-04-17T08:58:16.414Z"),
"day" : 17
}]
Ignore the day field projected during your process...
With reg_date in string you can't query for day of month as it only works with ISODate. I suggest first you convert the string in reg_date in all your documents with a script.
Then the following query should work
customer.aggregate([
{
$project:{
"document": "$$ROOT", //to get the whole document
"day":{$dayOfMonth:"$date"} //put day of month in 'day'
}
},
{
$match:{
"day": 17 //match 17
}
},
], function(data) {
for (var key in data.length) {
sendTheSMS(key[data]);
};
})
Use greater than and less than
var previousDate =new Date(2017, 1, 16); //month starts with 0
var nextDate=new Date(2017, 1, 18);
customer.find({reg_date : { $gt:previousDate,$lt:nextDate}})
.then(function(data) {
for (var key in data.length) {
sendTheSMS(key[data]);
};
});
Since reg_date is stored as a string, and not a Date/ISODate, you're limited as to what kind of query you can run (so I concur with the comment in one of the other answers that you should consider converting them to proper ISODate).
Considering that you want to query a date string for entries with a particular day-of-month, you can use a regular expression query:
customer.find({ reg_date : /-17T/ })
Or, dynamically:
let today = new Date();
let dom = ('00' + today.getDate()).slice(-2); // zero-pad day of month
let re = new RegExp('-' + dom + 'T');
customer.find({ reg_date : re })
You should also read this regarding speed optimizations, but still, regex queries aren't very fast.

Use zscan on score

According to this https://github.com/NodeRedis/node_redis/issues/896
I have zset , i am saving tokens(element) to corresponding timestamp(score)
Now i want to delete tokens older than particular timestamp using zscan.
redis.zscan('my_key', cursor[i], 'MATCH', '*', "COUNT", count, function(err,
console.log(err);
console.log(reply);
});
Problem i am having is zscan will return all the values irrespective of timestamp.
This 'MATCH' paramter checks the pattern on elements(token).
I want to get all the tokens older than some particular timestamp(score).
For example :
var startingTime = new Date().getTime();
redis.zrangebyscore("iflychat_auth_token", 0, startingTime - 43200000 * 2 * 7, function (error, data) {
// This will return all token older the 7 days.
});
Is there a way to use 'MATCH' on score
Something like this
redis.zscan('my_key', cursor[i], 'MATCH', < timestamp, "COUNT", count, function(err,
console.log(err);
console.log(reply);
});
ZSCAN doesn't have a score range option. The simplest alternative is using Redis' ZREMRANGEBYSCORE, possibly like so:
redis.zremrangebyscore('my_key','-inf', timestamp, function(error,data) { ... });
Note: if you need an exclusive range, i.e. < timestamp, prepend it with a ( when sending the value.

Resources