【MongoDB】数据的自动过期,TTL索引

文章目录

1. 前言

在近期的工作中,使用了MongoDB来保存了一些日志数据,但是这些日志数据具有一定的时效性,也就是按照业务的需要,保存xx天即可,在超过了这个时间之后,需要删除过时的日志。

按照之前的做法,可以使用定时任务,例如:Spring的定时器,xxl-job等工具,在每天凌晨的时候删除数据,这种方法虽然可行,但是需要额外的编码工作。

那有没有一种方式能够简单的搞定过期数据的清理呢?

当然,MongoDB提供了一种TTL索引的机制,可以非常方便的处理这种需求,下面是官方文档,有阅读能力的同学可以直接看这个文档。
《Expire Data from Collections by Setting TTL》

2.概念与使用

TTL的全称为 "Time To Live ",就是存活时间的意思,这是计算机中一个非常常见的概念,经常用于一些需要延时处理的任务,熟悉消息队列的同学肯定知道,延时队列实际上也是TTL的一种实践方式。

结合这个概念,MongoDB通过给数据创建TTL Index 也就是TTL索引的方式,在完成数据的过期和清理的任务。

2.1.使用方式

TTL Index 的使用方法的非常简单,只需要找到一个 日期类型 字段,给这个字段创建索引,并指定存活时间(expireAfterSeconds)就可以了。

我这里使用的MongoDB版本是最新的7.0.6,可以通过db.version();查看当前的版本号,太低的版本可能不支持这个功能。


先准备一条数据,然后创建索引:

js 复制代码
db.log_test.insertOne({
   "createTime": new Date(),
   "msg": "Success!"
})

db.log_test.find();
js 复制代码
db.log_test.createIndex({ "createTime": 1 }, { expireAfterSeconds: 10 });

db.log_test.getIndexes();

这里的expireAfterSeconds设置的是存活时间,单位:秒,在设置完成后,createTime与当前系统时间的差值大于 10s 的数据,将会被清理掉。是不是非常简单。

2.2.数组中包含日期字段

在上面已经创建索引的基础上, 看一下下面这个语句:

js 复制代码
db.log_test.insertOne({
   "createTime": [new Date(),'asdf',111],
   "msg": "Success!"
});

猜一下,这样的数据还能够被自动清理吗?

实际上,这种数据会可以被自动清理的,即使字段值是一个数组,但它包含了日期类型的字段,TTL索引都能够生效。

那再进一步,如果数组中包含了多个日期字段呢?该使用哪一个日期呢?例如:

js 复制代码
db.log_test.insertOne({
   "createTime": [new Date,ISODate("2024-04-20T13:48:18.428Z")],
   "msg": "Success!"
});

这种情况,数据也会在10秒后被删除掉。无关乎日期的大小,只要有任意一个日期满足过期的要求,就可以被删掉。

2.3.设置具体的过期时间点

上面说的都是设置一个数据的存活时间,不是固定的过期时间,如果想要设置固定的过期时间也非常简单,只需要把索引做一下变换。

js 复制代码
db.log_test.createIndex({ "expireTime": 1 }, { expireAfterSeconds: 0 });

expireAfterSeconds设置为0,然后在expireTime字段上设置具体的时间就可以了。

2.4.额外的过滤条件

上述的情况都是针对全量的数据做过期处理,但可能有的时候我们可能想保留有些有价值的数据,这部分数据不加入自动过期的逻辑。这个时候可以在创建索引的时候加入部分过滤条件,如下:

js 复制代码
db.log_test.createIndex(
    {"createTime": 1},
    {
        name:"canExpireDataTTL",
        partialFilterExpression:{"canExpire":true}, // canExpire=true的字段会过期自动清理
        expireAfterSeconds: 10
    }
);

接下来插入两条数据:

js 复制代码
db.log_test.insertOne({
   "createTime": [new Date()],
   "msg": "Success!",
   "canExpire":true
});

db.log_test.insertOne({
   "createTime": [new Date()],
   "msg": "Success!",
   "canExpire":false
});

按照预期,在10秒后,canExpiretrue的数据将会被清理,false的数据将会保留。验证结果如下:

3.总结

TTL索引可以在不添加新的代码逻辑的情况下,非常简单清理已过期的数据,只需要在日期类型的字段上创建TTL Index就可以了,即使这个字段是数组,只要数组中有日期也可能生效。

需要注意的是:过期数据的清理工作是由MongoDB的后台线程周期性执行的,一般这个周期是60s执行一次 ,如果发现上述的数据在 10秒后还没有被删除的话也不用惊慌,数据将会在60s的周期内被清理掉。

相关推荐
zpjing~.~25 分钟前
Mongo 分页判断是否有下一页
数据库
2401_8576009526 分钟前
技术与教育的融合:构建现代成绩管理系统
数据库·oracle
秋恬意1 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
潇湘秦1 小时前
一文了解Oracle数据库如何连接(1)
数据库·oracle
雅冰石1 小时前
oracle怎样使用logmnr恢复误删除的数据
数据库·oracle
web前端神器1 小时前
mongodb给不同的库设置不同的密码进行连接
数据库·mongodb
从以前1 小时前
Berlandesk 注册系统算法实现与解析
数据库·oracle
Muko_0x7d21 小时前
Mongodb
数据库·mongodb
Ren_xixi1 小时前
redis和mysql的区别
数据库·redis·mysql
m0_748233882 小时前
SQL语句整理五-StarRocks
数据库·sql