Finding documents using date arithmetic with Mongoose - node.js

I have a mongoose document which has these properties:
DocSchema = new Schema({
issue_date: Date,
days_to_expire: Number
});
DocSchema.virtual.get(function () {
return moment(this.issue_date).add(this.days_to_expire, 'days');
});
I want to find all document that are to expire within a week, is this possible with this schema definition?
The operation I'm looking for is something like this:
today - (issue_date + days_to_expire) <= 7
How can I query something like that using mongoose?

You'll be saving yourself a lot of trouble if you just store the expiration date inside the document as well. Then you're looking at a simple find({ expiration_date: { $gte: today, $lte: todayPlusSeven } }). Otherwise you're left calculating the expiration date in an aggregation and matching based off that.

Related

Mongoose query returning value even when not expecting it - using time cutoffs

I have a Mongoose query for a Mongo instance where I have a DB which contains a bunch of records where I want to get all documents where the 'stripe.trialEnd' is older than the current time but where the 'stripe.isPaid' value is false. I wrote this query and it seems to select fine based on the isPaid value but will always pick up a value for the cutoff. I am looking for how I can get this query to work correctly.
let cutoff = new Date();
Company.find({'stripe.trialEnd': {$lt: cutoff}, 'stripe.isPaid': { '$in': ['false', false]} })
Example DB document
{
_id: <123abc>
stripe: {
isPaid: false,
trialEnd: 1608943761 // Epoch time
}
...
}
A similar post that I modeled my query after: Querying with mongoose and dates
I think I solved the issue, so mongoose isn't converting the date to epoch time and therefore the compare is returning false all the time and giving me results. I changed how I create the date to give me epoch time seen below, that seems to have resolved the issue.
let cutoff = Date.now();

Mongoose Query: Compare one value with another transformed value of the same document

I need to query dates in the paidUntilDate property that are x days later than today, where x is in the property notificationDaysBefore of the same document. I'm using the dayjs library to query dates.
I found that I could compare values in the same document using $expr, but I don't know if I could use one of the values as a parameter to a dayjs .add() function and compare it to the other value.
Currently I have this query that gets paidUntilDate dates that are between 7-8 days from today.
const today = dayjs();
await Bed.find({
paidUntilDate: {
$lte: today.add(8, 'days'),
$gte: today.add(7, 'days')
}
})
I just need to replace the 7 with the values in the notificationDaysBefore property, and 8 with the 7 value +1.
Any help is appreciated. Thanks!
EDIT: I think I'm better off doing something like this:
await Bed.find({
}).where(today.diff('paidUntilDate')).in('notificationDaysBefore')
or
await Bed.find({
notificationDaysBefore: today.diff('$paidUntilDate', 'day'),
})
since notificationDaysBefore contains an array of numbers, but I still haven't figured out the correct syntax.
You can pass reference to notificationDaysBefore like this
const today = dayjs();
await Bed.find({
paidUntilDate: {
$lte: today.add(8, 'days'),
$gte: today.add('$notificationDaysBefore', 'days')
}
})

Passing current time to Mongoose query

I've run into problem. I made field in my Mongoose schema with type "Date":
...
timeOfPassingQuestion: Date,
...
Now, I want to pass current time in hours, minutes, seconds and miliseconds and save it into that field. How should I format my Node variable so I can pass it without errors?
Edit: Also, I forgot to say that I wanna later see how much time user spent answering question by subtracting current time and time that I pulled from DB, timeOfPassingQuestion field.
This is the syntax to create a schema that supports a date field:
// Schema
{ //...
someDate: Date,
}
// date object that you can use whenever you decide to set it
var dateObj = new Date();
This will create a JavaScript date object that you can then pass into your Mongoose object for the date field.
Or, if you will always want it on creation, put it directly in your mongoose schema
{ //...
createdDate: { type: Date, default: Date.now },
}
In order to compare the time in the future, I suggest you use moment.js, then you can query the time difference like so:
moment(Model.createdDate).fromNow();
Sources:
Mongoose Schema
Moment.js fromNow

Meteor: copy document to another collection and delete from original collection after 'expirationDate'

I am looking for an efficient way to publish blog posts if the expirationDate (which is a field in the blog document) has not passed the the current date.
The following is a simple working solution but please read below what I am aiming to do.
Meteor.publish('nonExpiredBlogs', function() {
var blogIds = []
var currentDate = new Date()
Blogs.find().forEach(function(doc) {
var expirationDate = doc.expirationDate
var hasExpDatePassed = (expirationDate - currenDate) < 0
if (hasExpDatePassed === false) { // expiration date is Not passed, get the doc _id
blogIds.push(doc._id)
}
});
return Blog.find({_id: {$in: {_id: blogIds}}});
}
I am wondering if there is an alternative where I dont need a 'forEach' function that may be quicker to compute.
For example, can I implement npm node-cron-jobs to check if the expirationDate has not passed servers current date, if so, simply copy the document to an 'Archive' collection and remove it from the Blogs collection.
I could use MongoDb's time to live for the delete operation, however, I dont know if or how the document can be copied to another collection first - This would be the ideal solution.
Just create query criteria which uses the $gt operator to compare documents that have the expirationDate field greater than the current date i.e. those documents that haven't yet expired:
Meteor.publish('nonExpiredBlogs', function() {
var currentDate = new Date();
return Blog.find({"expirationDate": {"$gt": currentDate}});
}

mongoose.js: finding data entries by day

Suppose this is your model:
var EventSchema = new Schema({
title: String,
startDate: Date,
endDate: Date
});
I would like to throw in a date (as simple as like '24-12-2012') and then retrieve every event that started or proceeded at that single day.
How do you do that?
Sure:
First read up on mongo query syntax for dates, here is a how-to for date ranges: http://cookbook.mongodb.org/patterns/date_range/
Then translate that mongo syntax into mongoose.
Event.where('startDate').lte(yourDate).exec(callback); //should do the trick
Now you just need to parse date strings to javascript dates. There are some cool libraries to do that, I believe that moment.js won't have a problem with that date string.
Oh, I forgot the last bit of magic: Put that query into a static method attached to your Event model, so from now on you can just call
Event.earlierThan(yourDate, callback); //Where your custom static is called 'earlierThan'.

Resources