Reputation: 4313
My goal is to update timeleft
field on every object in the itemSchema.
const ItemSchema = mongoose.Schema({
name: String,
time: { type: Date, default: Date.now },
timeleft: { type: Number, default: 24 }
});
For example in order for me to update every object in the ItemSchema
ItemSchema.methods.calculateTime = function() { // Done check it one hour
var currentTime = moment() // Get current Time
var timeStored = moment.utc(this.time).local().format(); // Convert this.time UTC to local time
var timeDiff = currentTime.diff(timeStored, 'h'); // See the difference in time example - 7
this.timeleft -= timeDiff; // Deduct timeleft witht he timeDiff , result would be 17
this.save(); // Simple save it to the database
}
API example
app.get('/allItems', function(req, res) {
Item.find({}, function(err, items) {
// I want to run items.calculateTime(); but it is not possible.
// How would I run calculateTime function on the array of objects?
});
});
My goal is to keep checking the time difference and save it to the time left
Data example
timeleft: 24
// after calculateTime
time: 17
Because I want to show this to the User
// 17 hours left
How would I do this to array of objects, instead of single object?
Upvotes: 0
Views: 356
Reputation: 11454
Looking at your use case I would suggest to modify your approach to the problem. Obviously you're creating items with an "expiry date" (or something similar, I'll be using the term "expired" in the following). The expiry is 24 hours from the time where the item was created.
I would not save the value for timeLeft
to the DB, but rather recalculate it dynamically upon querying. (1) It's redundant, as it can be calculated from the current time and the time
value, as far as I understood your question, (2) you would have to update the timeleft
property continuously which seems awkward.
You can make use of Mongoose's virtuals.
Changes to the Schema to make sure, that the virtuals are returned when creating objects:
const ItemSchema = mongoose.Schema({
name: String,
time: { type: Date, default: Date.now }
}, {
// enable, to have the property available,
// when invoking toObject or toJSON
toJSON: {
virtuals: true
},
toObject: {
virtuals: true
}
});
Define the virtual property timeLeft
(I changed the code to work without moment
):
// the virtual property, which is not stored in the DB,
// but calculated after querying the database
ItemSchema.virtual('timeLeft').get(function() {
var millisecondsDifference = Date.now() - this.time.getTime();
var hoursDifference = millisecondsDifference / (1000 * 60 * 60);
return Math.max(0, 24 - hoursDifference); // cap to 24 hours
});
You cannot query on virtual properties, because they obviously do not exist in the database. Instead, when you want to query for items which have reached their expiry date, you can search for items which have been created within the last 24 hours. In order to do that conveniently and have that code at a central place, you can attach a static method to your schema, which you can call using ItemModel.findNonExpired
:
// put the logic for querying non-expired items into
// its own static function, which makes it easier to
// reuse this functionality and understand what's going on
ItemSchema.statics.findNonExpired = function(callback) {
return this.find({
time: {
// find items which have a time within
// the last 24 hours
$gt: new Date(Date.now() - 1000 * 60 * 60 * 24)
}
}, callback);
};
const ItemModel = mongoose.model('Item', ItemSchema);
Demo:
// create and save some some test items
const items = [
{ name: 'created now' },
{ name: 'created an hour ago', time: new Date(Date.now() - 1000 * 60 * 60) },
{ name: 'created yesterday', time: new Date(Date.now() - 1000 * 60 * 60 * 24) },
{ name: 'created two days ago', time: new Date(Date.now() - 1000 * 60 * 60 * 24 * 2) },
];
ItemModel.create(items, function(err) {
if (err) throw err;
ItemModel.findNonExpired(function(err, items) {
if (err) throw err;
console.log(items);
});
});
[edit] This is now a full walkthrough, which you should be able to copy and paste without requiring any big changes.
Upvotes: 3