MongoDB提供了所谓的Time To Live 特性,使用这一特性,可以实现一些比较实用的功能,比如:会话管理、循环日志、临时记录自动清理等等。
下面介绍下如何使用MongoDB的TTL(Time To Live):

使用TTL的必要条件

  1. 必须要给Collection建立一个TTL的索引,并且在建立索引的时候要指定参数expireAfterSeconds。
    举例说明:
    expireAfterSeconds参数不为0的情况
db.my_collection.createIndex({'expire': 1}, {expireAfterSeconds: 30})
//给my_collection建立一个TTL索引索引,过期时间为30秒
db.my_collection.insert({'name':'张三', 'expire': new Date()})
//上面的这个文档(记录)将在当前时间30秒后被删除

上面的命令将建立一个TTL索引,表示文档将在expire字段指定的时间(如new Date时间是:2023-10-10 12:00:00)30秒后被清理,也就是2023-10-10 12:00:30后记录将被清理。

expireAfterSeconds参数为0的情况
也可以指定expireAfterSeconds的值为0,那么,文档(记录)将在expire指定的时间后被清理。
例如:

db.my_collection.createIndex({'expire': 1}, {expireAfterSeconds: 0})
//给my_collection建立一个TTL索引索引,过期时间为0秒
db.my_collection.insert({'name':'张三', 'expire': new ISODate("2023-10-10T12:00:00.000Z")})
//上面的这个文档(记录)将在指定的时间"2023-10-10T12:00:00.000Z"后被清理
  1. TTL不能使用复合索引,也就是只能指定一个字段。文档中如果没有这个字段的值,记录也是不会被清理的。
  2. Python中,索引指定的属性(字段)必须要使用utc time:
#建立索引
my_collection.create_index(keys=[('expire', pymongo.ASCENDING)], expireAfterSeconds=30, name='idx_expire')
#插入数据
utc_time = datetime.datetime.utcnow()
my_collection.insert_one({"name": '张三', "expire": utc_time}
#一定要注意使用

使用TTL的坑,注意它并不会及时清理

可能是性能的考虑,mongodb使用后台线程定时做超时数据的清理工作,因此,数据清理并不及时,清理的时间间隔大概在几十秒,所以,如果对超时时间要求比较严格的场景,比如:验证码之类的,就不能百分之百信任这个超时时间。比较安全的一种做法,在查询的时候是否存在的时候,把超时字段也作为查询条件。
用Python代码举例:

建立索引,expireAfterSeconds设置为0,这种方式比较灵活,每个文档(记录)的超时时间都可以不一样

my_collection.create_index(keys=[('expire', pymongo.ASCENDING)], expireAfterSeconds=0, name='idx_expire')

插入数据,设置30秒后过期

utc_time = datetime.datetime.utcnow()+datetime.timedelta(seconds=30)
my_collection.insert_one({"name": '张三', "expire": utc_time}

查询的时候,要注意把expire作为条件,不然mongodb的清理工作还没执行的时候,虽然超时了,但仍然能查得到数据

utc_now = datetime.datetime.utcnow()
my_collection.find({"name":'张三', "expire":{"$gt": utc_now}})