MongoDB - Updating TTL Index value - mongodb

I'm trying to update the value of the expiry date in a document. Here's the Node.js code I use to set the index everytime I want to update the document:
database.collection(collectionName).createIndex({ "expires_on": 1 }, { expireAfterSeconds: 0 })
database.collection(collectionName).updateOne(query, update, { upsert: true }, (error, result) => {...})
The thing is that I set the expires_on date to the date of tomorrow and the value is set correctly in database but it expires within a few seconds. Is there a problem with the way I'm updating this field? I don't know how I can update this document in a way that it would expire on the last expires_on date it has been updated for.
I have noticed that you can't update the indexes in MongoDB but am I updating the index here? Isn't it different when I try to change the value, not the index itself?

You have understood ttl index bit strange way...
In your code example you set every document what have timestamp column "expires_on" to expire right now (expireAfterSeconds: 0).
Expiring process is running background and if you set expireAfterSeconds to 0, it will find out all documents which "expires_on" value is less or equal to now().
So, your update of field "expires_on" must happen at moment where "now() -lt expires_on".
Better say f.ex. "expireAfterSeconds: 3600" and then update expires_on to value "tomorrow minus that 3600 seconds"...

The fact I was creating an index every time a new data was inserted was not logical. I set the index in my database once and only updated the document each time:
database.collection(collectionName).updateOne(query, update, { upsert: true }, (error, result) => {...})
However, the problem turned out to be the value I set for the expires_on in my code. Due to the asynchronicity of Node.js, the value wasn't calculated correctly.

Related

Auto-update field after specific amount of time only when specific conditions are met

Mongodb has an option to set TTL on documents.
I would like to know if there is a similar feature that allows the update of a specific field after a specific amount of time.
Basically what I want to achieve is update the field STATUS of a document from PENDING to EXPIRED after a specific amount of time (only if it was PENDING).
I know I could use cronjobs, but first I want to check whether it's possible natively with Mongodb.
Furthermore, is it possible to set the TTL with condition? Like deleting a document after X days only if STATUS is EXPIRED?
what I want to achieve is update the field STATUS of a document from PENDING to EXPIRED after a specific amount of time
Not achievable today, you have to create your own script
Furthermore, is it possible to set the TTL with condition? Like
deleting a document after X days only if STATUS is EXPIRED?
I recommend you that the script that set the status also set readyToBeDeletedSince: Date and that you put your TTL on that field.
Regarding the TTL with condition, I found that there is an option called "partialFilterExpression" that you can add to the index.
For example the following will delete a document after 5 minutes only if status is "PENDING"
db.mymodel.createIndex({ createdAt: 1 }, { expireAfterSeconds: 300, partialFilterExpression: { status: 'PENDING' } })

How to write a query in Mongo to remove records where DateTimeOffset is greater than 30 days

A capture from mongoDb with the structure of a Date time
You can set TTL indexes while creating your records.TTL indexes are special single-field indexes that MongoDB can use to automatically remove documents from a collection after a certain amount of time or at a specific clock time.
To create a TTL index, use the db.collection.createIndex() method with the expireAfterSeconds option on a field whose value is either a date or an array that contains date values.
For example, to create a TTL index that removes the record after 30 days on the createdDate field of the User collection, use the following operation in the mongo shell:
db.User.createIndex( { "createdDate": 1 }, { expireAfterSeconds: 2592000 } )
src: https://docs.mongodb.com/manual/core/index-ttl/

How to get remaining TTL for mongo Document

I have created one collection in mongoDB for which i have created index for field "expireAt" which is a date time and set expireAfterSeconds property to 0.
As i want to set TTL at document level not at collection level.
As i know in redis i can get the remaining TTL for the particular key
Just have question is that possible in mongoDB ? where i can get the remaining time to expire for the given document.
I have searched it on google but didn't find any relevant information.
Thank You
If you set the TTL expireAfterSeconds value to 0 for per-document expiry, the remaining time will be the difference between the current time and the TTL date field (eg. expireAt) in your documents. There isn't a specific server function to query this, but you can either calculate this in your app or use MongoDB's aggregation framework.
Example using the mongo shell to return the time left (in milliseconds) before documents are eligible to be removed in the next TTL pass:
db.mycoll.aggregate(
{ $project: {
expireAt: 1,
ttlMillis: {
$subtract: [ "$expireAt", new Date() ]
}
}}
)
Note: The TTL background thread runs every 60 seconds, so documents may persist for a minute or more past their nominal expiry.
try this
db.hellos.createIndex( { "expireAt": 1 }, { expireAfterSeconds: 3600 } )
read more here

How to handle an 'lastModified' field in a mongodb collection?(In such a way that the field gets updated only if any value in the document is changed)

EDIT(15/04/2016): As per the comments received in this question I think there is no direct method in mongodb to do so. In that case is it possible to do this with MongooseJS?
I am using mongodb, For one collection I need an 'lastModified' field, which should show me when in the last time any value of the document actually modified. That means, If I did an update query and all the other values are same, then the 'lastModified' shouldn't get updated.
Example:
Suppose I have a document in collection as :
{ _id: 1, status: "a", lastModified: ISODate("2016-04-02T01:11:18.965Z") }
when I update with
{$set:{"status":"a", "lastModified":"Current Time Here"}}
then the "lastModified" should not change
when I update with
{$set:{"status":"b", "lastModified":"Current Time Here"}}
then the "lastModified" should change
How to achieve this?
In my case I will call the update operation multiple times, and I don't want to get the 'lastModified' changed each in this case. Instead it should change only when the 'status' is actually modified.

Expire a Collection in Mongo using Casbah EnsureIndex

I am attempting to expire a collection in Mongo using Casbah's ensureIndex API.
Based on this document
http://docs.mongodb.org/manual/tutorial/expire-data/
I am using casbah's proposed ensureIndex API
collection.ensureIndex(DBObject("status" -> 1, "expireAfterSeconds" -> 120))
to expire the collection in 2 minutes ...
The collection is not being evicted or expired.
Am I missing anything else here?
Thanks
There are a couple things to check:
Were you just following the docs to a T and tried to create an index on a status field which doesn't actually exist in your documents? (had to atleast ask...)
Does the status field contain JUST dates? It can theoretically be mixed, but only documents with a date type would be considered for expiration.
Have you checked your collection indexes to make sure the index was properly created?
To check for the index from the console run: db.collection.getIndexes(). If the index was created successfully, then double check you have the corresponding status fields in your documents and that they are proper dates.
Adding the index alone, doesn't create the date field for you - you would need to add it to the documents or use an existing date field that is not part of any other index.
Also note, from the docs:
TTL indexes expire data by removing documents in a background task
that runs every 60 seconds
So, if you have a 120 second expiration, bear in mind, that its possible the documents could remain for 120 seconds up to 179 seconds, give or take, depending on when the document expired and the background task last ran.
edit: As noted in the comments - a collection itself cannot be removed based on a TTL index, the index only expires the documents in the collection.
I think, you are passing the Options in the wrong way.
It should be-
collection.ensureIndex(DBObject("status" -> 1), DBObject("expireAfterSeconds" -> 120))
Instead of-
collection.ensureIndex(DBObject("status" -> 1, "expireAfterSeconds" -> 120))