Always getting same timestamp - createdOn for different new entires in MongoDb - node.js

Below is my mongoose Schema out of which createdOn is of type date and default to Date.now().
const SurveyResponseModel = mongoose.Schema({
surveyId: { type: String, required: true },
surveyData: [surveyData],
result : [respResult],
patientId: { type: String },
surveyBy: {type: String},
createdOn: { type: Date, default: Date.now() },
});
Here is how I'm adding new entries to the db.
const newSurvey = new surveyResponseModel({ surveyId, surveyData, surveyBy, patientId, result })
let savedSurvey = await newSurvey.save();
Up until here everything works fine. The problem starts when new entries are made into the schema. I get the same timestamp of createdOn for each new entries.
What am I doing wrong? Is it createdOn: { type: Date, default: Date.now() } a issue or something else. Is it a problem with MongoDB or my node express server? Some help and feedback would really be appreciated.

When this code is executed (at server startup), Date.now() is executed and the result is saved in the object literal, hence that single timestamp will be used for the duration of the server's life.
Try passing the function instead of a value it returns at a single point in time. Mongoose will then call it at runtime.
createdOn: { type: Date, default: Date.now }

Related

How to search Mongodb models by date?

I am using Node.js mongodb. I have a model like this
const calendarSchema = new Schema ({
title: String,
start: String, //start date
end: String, // end date
endDate: String,
sessionsRan: Number,
_user: {type: Schema.Types.ObjectId, ref: 'User' },
created: {
type: Date,
default: Date.now
},
})
What is the best way to query mongodb for this? I need to find documents where date < today and isActive: true.
I am currently doing this but not sure how implement a date search
const calendar = await Calendar.find({isActive: "active"})
With $lt mongodb operator, you can query against the date field alongside isActive field.
{start:{$lt: new Date().toISOString()}, isActive: true}
Here's a live demo
Note:
Ensure your dates are saved as ISOString
Your schema for dates should be constructed with new Date() object rather than a String.

Mongoose - Set TTL on MongoDB Document

I am trying to set a TTL via mongoose when a document is created in MongoDB, but I'm not having any luck with any of my attempts. Latest version of mongoose is being used in my project and from what I can tell I've tried the most common answers here on SO and elsewhere online.
My Schema
const mongoose = require('mongoose');
const jobSchema = new mongoose.Schema(
{
positionTitle: {
type: String,
},
description: {
type: String,
}
});
const Jobs = mongoose.model('job', jobSchema);
module.exports = Jobs;
I have tried adding a createdAt with expires based on this question answer:
const jobSchema = new mongoose.Schema({
positionTitle: {
type: String,
},
description: {
type: String,
},
createdAt: { type: Date, expires: 3600 },
});
Along with this option that's also in the same question to have createdAt be created automatically via timestamps:
const jobSchema = new mongoose.Schema(
{
positionTitle: {
type: String,
},
description: {
type: String,
},
},
{ timestamps: true }
);
Trying variations of the following to set an index with timestamps defined:
jobSchema.index({ createdAt: 1 }, { expires: 86400 });
jobSchema.index({ createdAt: 1 }, { expires: '1 day' });
jobSchema.index({ createdAt: 1 }, { expireAfterSeconds: 3600 });
Regardless of which option I try, the document is removed after MongoDB's 60-second cycle when a createdAt field is set on the document. Would really love to know what I'm doing wrong.
After trying all the solutions in the thread you mentioned, none of them worked. In the end this code did the trick. It involves setting the expireAt field to the actual time that you want it deleted, which makes sense really.
const Schema = mongoose.Schema;
const YourSchema = new Schema({
expireAt: {
type: Date,
default: Date.now() + 10 * 60 * 1000 // expires in 10 minutes
},
});
This is the only thing that worked, all the other solutions I tried always deleted after 1min, no matter the amount of time I added.
I've been having issues with this as well. I found this thread here https://github.com/Automattic/mongoose/issues/2459 and it worked for me. Translated into your code would look like this.
const mongoose = require('mongoose');
const jobSchema = new mongoose.Schema(
{
positionTitle: {
type: String,
},
description: {
type: String,
},
expireAt: {
type: Date,
default: Date.now,
index: { expires: '5s' }
}
});
const Jobs = mongoose.model('job', jobSchema);
module.exports = Jobs;
On the link I added, it is the very last solution. I'm not exactly sure what this is doing but here is the mongo link of what it should be doing for anyone else with this issue. https://docs.mongodb.com/manual/tutorial/expire-data/. To change the amount of time that you need the document just change the expires. It accepts '#s' and '#d' for sure. Also if you want your document to be deleted at a specific time then you can do this.
expireAt: {
type: Date,
default: new Date('July 22, 2013 14:00:00'),
index: { expires: '0s' }
}
This will delete the document 0 seconds after the specified date.
Problem in TTL, Reason behind Document does not delete after some / few seconds, how to expire document in MongoDB / Mongoose using schema. Solution expireAfterSeconds / expires / index.
NOTE: - MongoDB's data expiration task runs once a minute, so an expired doc might persist up to a minute past its expiration. This feature requires MongoDB 2.2 or later. It's up to you to set createdAt to the current time when creating docs or add a default to do it for you as suggested here.
NOTE :- Below code is working fine and the document will delete after 5 minutes.
const verficationSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
lowercase: true,
trim: true,
validate(email) {
if (!validator.isEmail(email)) {
throw new Error("Email is not valid!");
}
},
},
otp: {
type: Number,
required : true
},
expireAt : {
type: Date,
default: Date,
expires : 300 // means 300 seconds = 5 minutes
}
});
NOTE :- Upper code is working fine, But document will delete after 1 minutes, because MongoDB check expiration procedure after every 1 minutes.
const verficationSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
lowercase: true,
trim: true,
validate(email) {
if (!validator.isEmail(email)) {
throw new Error("Email is not valid!");
}
},
},
otp: {
type: Number,
required : true
},
expireAt : {
type: Date,
default: Date,
expires : 8 // means 8 seconds
}
});

Mongoose Schema how to change date.now whenever DB is updated

How Can we change the value of updated_at whenever Data of DB is updated
Consider this to be my Mongoose Schema,
const mongoose = require('mongoose')
const locationDataSchema = new mongoose.Schema({
locationName: String,
location: [{
lat: Number,
lng: Number
}],
news: [ {
author: String, //or number
title: String,
description: String,
url: String,
urlToImage: String
}],
updated_at: {
type: Date,
default: Date.now
}
})
From my Vaguely reading of Mongoose Docs, I did something like this
locationDataSchema.post('save', (next) => {
console.log("here")
this.locationName = this.locationName.toLowerCase();
this.updated_at = Date.now()
})
But this isn't being called whenever I create/update something in my mongoose Schema
Question: Can someone help me in figuring out how can I change
updated_at = Date.now()
Whenever user updates data in DB (similarly changing location Name to Lowercase)
The current version of Mongoose (v4.x) has time stamping as a built-in option to a schema:
var mySchema = new mongoose.Schema( {name: String}, {timestamps: true} );
This option adds createdAt and updatedAt properties that are timestamped with a Date, and which does all the work for you.
For more please look at
https://mongoosejs.com/docs/guide.html#timestamps

How do I set a document to expire using Mongoose (Node.js)? [duplicate]

Below is the command that can be used via the mongo terminal to set an expiry time for collections (a TTL):
db.log.events.ensureIndex( { "status": 1 }, { expireAfterSeconds: 3600 } )
How do I do this from my code in Node.js using mongoose?
In Mongoose, you create a TTL index on a Date field via the expires property in the schema definition of that field:
// expire docs 3600 seconds after createdAt
new Schema({ createdAt: { type: Date, expires: 3600 }});
Note that:
MongoDB's data expiration task runs once a minute, so an expired doc might persist up to a minute past its expiration.
This feature requires MongoDB 2.2 or later.
It's up to you to set createdAt to the current time when creating docs, or add a default to do it for you as suggested here.
{ createdAt: { type: Date, expires: 3600, default: Date.now }}
this code is working for me.
may it help
let currentSchema = mongoose.Schema({
id: String,
name: String,
packageId: Number,
age: Number
}, {timestamps: true});
currentSchema.index({createdAt: 1},{expireAfterSeconds: 3600});
Providing a string to expires also works nicely with Mongoose if you do not want to deal with the expire time calculation and improve the overall readability of the schema.
For example here we are setting the expires to 2m (2 minutes) and mongoose would convert to 120 seconds for us:
var TestSchema = new mongoose.Schema({
name: String,
createdAt: { type: Date, expires: '2m', default: Date.now }
});
Mongoose would create an index in the background and auto set the expireAfterSeconds to in this case 120 seconds (specified by the 2m).
It is important to note that the TTL process runs once every 60 seconds so it is not perfectly on time always.
If you are working with Mongodb Atlas Replica Sets - try:
import * as mongoose from 'mongoose';
let currentSchema = new mongoose.Schema({
createdAt: { type: Date, expires: 10000, default: Date.now },
id: String,
name: String,
packageId: Number,
age: Number
});
currentSchema.index({"lastModifiedDate": 1 },{ expireAfterSeconds: 10000 });
new Scehma({
expireAt: {
type: Date,
expires: 11,
default: Date.now
}
)}
This is the solution that worked for me according to this in the current Mongoose docs.
There is a npm library - 'mongoose-ttl'.:
var schema = new Schema({..});
schema.plugin(ttl, { ttl: 5000 });
you can see all the options of this library:
https://www.npmjs.com/package/mongoose-ttl
const Schema = new mongoose.Schema({id: {
type: Number},
createdAt: {
type: Date, expires: '4h', index: true,
default: Date.now}});
You need to add index: true while creating you schema
9/2022 Working Solution using Mongoose 6.5.4
None of the answers here worked for me, but I was able to finally get it working using the latest version of Mongoose currently available, 6.5.4.
Say our Schema looks like this:
const MySchema = new mongoose.Schema({
id: { type: Number },
myCustomTTLField: { type: Date }
});
myCustomTTLField is the field you want to index and have control the expiration. To achieve this, we add the following under our schema definition:
MySchema.path('myCustomTTLField').index({ expires: 60 });
The argument in MySchema.path is the name of the field you want to index for TTL. The expires option should be the number of seconds that will elapse from the Date represented in myCustomTTLField before the document is deleted. In the example above, the document will be deleted 60 seconds after whatever date is saved in myCustomTTLField. The full example:
const MySchema = new mongoose.Schema({
id: { type: Number },
myCustomTTLField: { type: Date }
});
MySchema.path('myCustomTTLField').index({ expires: 60 });
Please let me know if this works for you, I hope this helps. Mongoose TTL has been a thorn in my side for a long time, as their docs are notoriously tough to navigate. I found this solution via a small example buried in the docs here.
IMPORTANT NOTE:
TTL is not guaranteed to happen at exactly the time specified by your date + expiration seconds. This is due to how MongoDB's background delete process works. It runs every 60 seconds, so you may theoretically wait up to 60 seconds past expected TTL before seeing your document deleted. More info on that from the MongoDB docs.
FWIW I could only get the expires feature to work on a field called expiresAt. Here's my interface, and schema for implementing this in Typescript.
import { model, Schema, Types } from 'mongoose';
export interface ISession {
sessionId: string;
userId: Types.ObjectId;
role: string;
expiresAt?: Date;
}
const sessionSchema = new Schema<ISession>({
sessionId: { type: String, required: true, indexes: { unique: true} },
userId: { type: Schema.Types.ObjectId, required: true, ref: 'users'},
role: { type: String, required: true, enum: [ 'ADMIN', 'BASIC_USER' ]},
expiresAt: { type: Date, expires: '1h', default: Date.now }
}, { versionKey: false });
Reading the Mongoose documentation it seems like all the other proposed solutions should work too. I don't know why they were not for me. You can read the official Mongoose docs on expiresAt here.

Which SchemaType in Mongoose is Best for Timestamp?

I'm using Mongoose, MongoDB, and Node.
I would like to define a schema where one of its fields is a date\timestamp.
I would like to use this field in order to return all of the records that have been updated in the last 5 minutes.
Due to the fact that in Mongoose I can't use the Timestamp() method I understand that my only option is to use the following Javascript method:
time : { type: Number, default: (new Date()).getTime() }
It's probably not the most efficient way for querying a humongous DB.
I would really appreciate it if someone could share a more efficient way of implementing this.
Is there any way to implement this with Mongoose and be able to use a MongoDB timestamp?
Edit - 20 March 2016
Mongoose now support timestamps for collections.
Please consider the answer of #bobbyz below. Maybe this is what you are looking for.
Original answer
Mongoose supports a Date type (which is basically a timestamp):
time : { type : Date, default: Date.now }
With the above field definition, any time you save a document with an unset time field, Mongoose will fill in this field with the current time.
Source: http://mongoosejs.com/docs/guide.html
The current version of Mongoose (v4.x) has time stamping as a built-in option to a schema:
var mySchema = new mongoose.Schema( {name: String}, {timestamps: true} );
This option adds createdAt and updatedAt properties that are timestamped with a Date, and which does all the work for you. Any time you update the document, it updates the updatedAt property. Schema Timestamps Docs.
In case you want custom names for your createdAt and updatedAt
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schemaOptions = {
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
};
const mySchema = new Schema({ name: String }, schemaOptions);
var ItemSchema = new Schema({
name : { type: String }
});
ItemSchema.set('timestamps', true); // this will add createdAt and updatedAt timestamps
Docs: https://mongoosejs.com/docs/guide.html#timestamps
Mongoose now supports the timestamps in schema.
const item = new Schema(
{
id: {
type: String,
required: true,
},
{ timestamps: true },
);
This will add the createdAt and updatedAt fields on each record create.
Timestamp interface has fields
interface SchemaTimestampsConfig {
createdAt?: boolean | string;
updatedAt?: boolean | string;
currentTime?: () => (Date | number);
}
This would help us to choose which fields we want and overwrite the date format.
new mongoose.Schema({
description: {
type: String,
required: true,
trim: true
},
completed: {
type: Boolean,
default: false
},
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
}
}, {
timestamps: true
});
I would like to use this field in order to return all the records that have been updated in the last 5 minutes.
This means you need to update the date to "now" every time you save the object. Maybe you'll find this useful: Moongoose create-modified plugin
You can use timestamps:true along with toDateString to get created and updated date.
const SampleSchema = new mongoose.Schema({
accountId: {
type: String,
required: true
}
}, {
timestamps: true,
get: time => time.toDateString()
});
Sample doc in Mongo DB
First : npm install mongoose-timestamp
Next: let Timestamps = require('mongoose-timestamp')
Next: let MySchema = new Schema
Next: MySchema.plugin(Timestamps)
Next : const Collection = mongoose.model('Collection',MySchema)
Then you can use the Collection.createdAt or Collection.updatedAt anywhere your want.
Created on: Date Of The Week Month Date Year 00:00:00 GMT
Time is in this format.

Resources