7

as far i know, currently mongodb TTL are managed by expireAfterSeconds index and it's setting for all document inside a collection.

so is there any built-in way to set expiration to single document ?, thankyou

  • The TTL index is a general index. On that you are totally right. But the time to live is still computed on a per document basis since it's set based on a specifc field against which the index will be evaluated. Is that what you need? Or do you actually want to specify a different length of the ttl on a per document basis? – Manuel Zelenka Apr 25 '20 at 10:36
  • @ManuelZelenka i want more like redis, TTL/expireAfterSeconds specified in single document – Lobo Nokewe Ngewe Apr 25 '20 at 10:58
  • Then you're good to go with Kevins answer. Setting expireAfterSeconds to 0 and then simply defining in the indexed field of the document when it should expire is the way to go. – Manuel Zelenka Apr 25 '20 at 11:22

1 Answers1

18

On each documet you can set a field of expires and create the following index:

db.docs.createIndex( { expires:1 }, {expireAfterSeconds: 0 } );

documents inside this collection will get removed once time ticks over the expired field. However, this may take up 60 seconds as the background task that runs to remove documents runs every 60 seconds.

Here's an example though...

So let's insert a bunch of documents adding 60 seconds to each document each time we add them.

> var expires = new Date(); // Gets the current datetime.
> expires.setSeconds(expires.getSeconds() + 60)
1587812623023
> db.docs.insert({expires})
WriteResult({ "nInserted" : 1 })

> expires.setSeconds(expires.getSeconds() + 60)
1587812683023
> db.docs.insert({expires})
WriteResult({ "nInserted" : 1 })

> expires.setSeconds(expires.getSeconds() + 60)
1587812743023
> db.docs.insert({expires})
WriteResult({ "nInserted" : 1 })

> db.docs.find()
{ "_id" : ObjectId("5ea418de00f07c4d6461090b"), "expires" : ISODate("2020-04-25T11:03:43.023Z") }
{ "_id" : ObjectId("5ea418e300f07c4d6461090c"), "expires" : ISODate("2020-04-25T11:04:43.023Z") }
{ "_id" : ObjectId("5ea418e600f07c4d6461090d"), "expires" : ISODate("2020-04-25T11:05:43.023Z") }

Now if we add the TTL index.

db.docs.createIndex( { expires:1 }, { expireAfterSeconds: 0 } )

Then we can monitor our collection each 60 seconds and see each document getting removed.

> new Date()
ISODate("2020-04-25T11:03:28.278Z")
> db.docs.find()
{ "_id" : ObjectId("5ea418de00f07c4d6461090b"), "expires" : ISODate("2020-04-25T11:03:43.023Z") }
{ "_id" : ObjectId("5ea418e300f07c4d6461090c"), "expires" : ISODate("2020-04-25T11:04:43.023Z") }
{ "_id" : ObjectId("5ea418e600f07c4d6461090d"), "expires" : ISODate("2020-04-25T11:05:43.023Z") }

Nothing has been removed yet.

> new Date()
ISODate("2020-04-25T11:04:18.652Z")
> db.docs.find()
{ "_id" : ObjectId("5ea418e300f07c4d6461090c"), "expires" : ISODate("2020-04-25T11:04:43.023Z") }
{ "_id" : ObjectId("5ea418e600f07c4d6461090d"), "expires" : ISODate("2020-04-25T11:05:43.023Z") }

One document has gone.

> new Date()
ISODate("2020-04-25T11:05:17.705Z")
> db.docs.find()
{ "_id" : ObjectId("5ea418e600f07c4d6461090d"), "expires" : ISODate("2020-04-25T11:05:43.023Z") }

Another is gone.

> new Date()
ISODate("2020-04-25T11:06:31.390Z")
> db.docs.find()
>

and we're left with no doucments in our collection.

Kevin Smith
  • 13,746
  • 4
  • 52
  • 77
  • I spent zero time thinking about a solution to this :) Thanks Kevin and thanks SO! – VladFr Nov 01 '22 at 18:30
  • In Mongo 5.0+, `expireAfterSeconds` must be set to 1. If you set it to 0 it will default to disabling TTL expiration. – VladFr Nov 01 '22 at 18:44
  • Hey @VladFr, I can't find anywhere in the docs explaining this? can you provide a link please? https://www.mongodb.com/docs/manual/tutorial/expire-data/#expire-documents-at-a-specific-clock-time – Kevin Smith Nov 02 '22 at 09:33