Getting MongoDb document to expire at a certain time using mongoose [duplicate] - javascript

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.

Related

Mongoose timestamp gives inacurate results

CreatedAt gives the time 3 hours ago. How can i make it display the current time?
The schema:
import mongoose from 'mongoose';
var articleSchema = new mongoose.Schema({
title: String,
text: String,
link: String,
description: String,
imgLink: String,
source: String,
} , { timestamps: true }
);
articleSchema.index({ createdAt: 1, expires: '60m', default: Date.now });
var Article = mongoose.model("Article", articleSchema);
export default Article;
You probably getting different time zone from mongoose.
Try installing npm i moment-timezone
And change your Date to the right timezone, here is the docs for that: https://momentjs.com/timezone/docs/#/using-timezones/parsing-in-zone/

How to store a datetime using mongoose?

I made this to store data of some meetings but I want the field "date" to store values as datetime like in a mysql base. How can I do this?
const mongoose= require('mongoose')
const Schema= mongoose.Schema
const Meets= mongoose.model('Meet', new Schema({
id1: String,
id2: String,
date: Date
}))
module.exports= Users
Your schema should be in below format for store Meeting time in DateTime format.
const mongoose= require('mongoose')
const Schema= mongoose.Schema
const Meets= mongoose.model('Meet', new Schema({
// First meeting recipient
id1: { type: Schema.Types.ObjectId, required: true },
// Second meeting recipient
id2: { type: Schema.Types.ObjectId, required: true },
// Date and Time of meeting
date: { type: Date, required: true }
}))
module.exports= Meets
Now, When you will make an entry in Meets collection, You will find below format of date key in your mongo database:
ISODate("2017-04-02T15:30:00Z")
This represents that the above is in ISO Date format which gives time into UTC format. To convert it in your local time format, you can do below step:
new Date(meet.date).toLocaleString();
Also, you can set property {timestamps:true} in your schema, which will additionally add createdAt and updatedAt field in your collection, which will automatically get updated at creation and each update.
Thanks
What kind of date format you want to store? If you want it to be stored in milliseconds, then you can set timestamps option to true like this:
const Meets= mongoose.model('Meet', new Schema({
id1: {String},
id2: {String},
}, {timestamps:true}))

How do I add new keys to a Mongoose Schema?

I recently started developing an app for my senior project which requires me to use some type of database. For that I decided to go with Mongoose since it is noSQL and slightly easier to pick up.
So, fast forward and I run into a problem where I can't figure out how to edit an already existing Schema and add new keys into it.
For example, I have this Schema which represents a post(think Tweets or Facebook posts) that holds:
A string that holds the body of the post
The id of the user that created the post
The Date of when the post was created
My code for that is:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const PostsSchema = new Schema({
Value: {
type: String,
required: true
},
User: {
type: Schema.Types.ObjectId,
ref:'users'
},
Date: {
type: Date,
default: Date.now
}
});
// Create collection and add schema
mongoose.model('posts', PostsSchema, 'posts');
What I want now is to access that schema in some way and add a new key to it using something similar to maybe
PostsSchema.add({Private: { default: false}});
Meaning that, now the schema in the database will look something like:
{
"_id": {
"$oid": "1831g98af21n9s5u7s9ccchj5"
},
"Value": "Beautiful day outside, can't wait to go jogging!",
"User": {
"$oid": "9a79ab143lbk9lk55wq327oi3226m"
},
"Date": {
"$date": "2018-10-29T01:28:44.408Z"
},
"Private": "false"
"__v": 0
}
So back to my question, is there any way to do this? Or if you have a link to documentation of such methods I would greatly appreciate it. Thank you Greatly!
Just add the field to the schema with a default:
const PostsSchema = new Schema({
Value: {
type: String,
required: true
},
User: {
type: Schema.Types.ObjectId,
ref:'users'
},
Date: {
type: Date,
default: Date.now
},
Private: {type: Boolean, default: 'false'}
});
Since you have a default any new record will have it as well as any new instance of an old model saved before you added the private field.
If you really need more dynamic approach the usual recommendation is using Mixed Type with all the pluses and minuses that come with it.

Mongoose doesn't create TTL indexes

This is my Mongoose model:
var sessionSchema = new Schema({
_id: { type: String, required: true, index: { unique: true } },
user: { type: Schema.Types.ObjectId },
expire: { type: Date, index: { expireAfterSeconds: 21600 } }
})
module.exports = mongoose.model('Session', sessionSchema)
I need to be able to set a date object into expire (usually it's something like Date.now plus a few minutes) and have the object removed from the collection after 6 hours past the expiration.
However, I'm not able to have Mongoose to create the index. When I run db.sessions.getIndexes() in the mongo console, here's the output:
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "dev.sessions"
}
]
I've tried also with different syntaxes, like
expire: { type: Date, expires: 21600 } (Mongoose's short-hand version).
I tried also defining the index at the schema level:
sessionSchema.index({ expire: 1 }, { expireAfterSeconds: 21600 })
None is working.
Unlike others who asked questions on SO, my index is simply not created. I've tried also removing the collection and the database as well, and when they're recreated they still don't contain the index.
Versions: Mongoose 3.8.19, MongoDB 2.6.5 (OSX) and Node.js 0.10.33
Edit
More info: I tried creating the index directly from the mongo console, with:
db.sessions.ensureIndex({"expire":1}, {expireAfterSeconds: 21600})
That appears to be working (the index is created).
However, it's not working with Mongoose in any way.
Apparently the problem was that I created an index on the custom _id field. MongoDB creates an index on that field by itself, so when Mongoose was calling ensureIndex to create also the TTL index, it failed for both.
See https://github.com/LearnBoost/mongoose/issues/2459

Automatic createdAt and updatedAt fields in Meteor

In my collection I'd like to have automatically generated createdAt and updatedAt fields that would contain the date of when the object was inserted / updated for the last time - kind of like it's happening in Ruby on Rails. Currently I'm doing this with an observer similar to this one:
MyCollection.find({}).observeChanges({
changed: function(id, changes) {
MyCollection.update(id, ...);
},
});
Is there a better / more efficient / more straightforward way?
I use Collection2. It supports autoValue in the schema, a function that computes the forced value of a field. As these two fields are used in all collections, you can save them to a variable:
#SchemaHelpers =
createdAt:
type: Date
autoValue: ->
if #isInsert
return new Date
if #isUpsert
return $setOnInsert: new Date
if #isUpdate
#unset()
return
updatedAt:
type: Date
autoValue: ->
return new Date
And then in the collection:
Schema = {}
Posts = new Meteor.Collection("posts")
Schema.Posts = new SimpleSchema
createdAt: SchemaHelpers.createdAt
updatedAt: SchemaHelpers.updatedAt
title:
type: String
max: 30
body:
type: String
max: 3000
Posts.attachSchema(Schema.Posts)
This solution makes updatedAt always present and its value will be very close to createdAt when it is just inserted (not necessarily the same). If you need updatedAt not to be set when inserting, you can use something like the example in the Collection2 readme:
updatedAt: {
type: Date,
autoValue: function() {
if (this.isUpdate) {
return new Date();
}
},
denyInsert: true,
optional: true
},
but this does not handle upserts. I don't know any good solution that handles upserts correctly and leaves the field empty at inserts.
I like https://github.com/matb33/meteor-collection-hooks
collection.before.insert (userId, doc) ->
doc.createdAt = new Date().valueOf #toISOString()

Categories