使用Mongoose的expires实现Token过期时移除Driver中关联的ObjectId引用
实现方案
该功能完全可以实现,首先需要注意一个核心坑点:Mongoose 的文档删除中间件仅在应用层主动调用删除方法时触发,MongoDB 后台 TTL 索引自动执行的删除操作不会触发这类中间件,因此不能直接用普通的 schema 中间件实现需求。
以下是两种可行的落地方案:
方案1:使用 MongoDB Change Stream 监听删除事件(推荐)
MongoDB 3.6及以上版本支持的 Change Stream 可以监听集合的所有数据变更事件,覆盖TTL自动删除、手动删除等所有删除场景,捕获事件后同步更新Driver文档即可。
实现代码:
const Token = mongoose.model('Token', tokenSchema); const Driver = mongoose.model('Driver', driverSchema); // 监听Token集合的变更事件 const tokenChangeStream = Token.watch(); tokenChangeStream.on('change', async (change) => { // 仅处理删除类型的变更 if (change.operationType === 'delete') { const deletedTokenId = change.documentKey._id; // 同步清空所有关联Driver文档的token引用 await Driver.updateMany( { token: deletedTokenId }, { $unset: { token: "" } } ); } });
注意事项:
该方案要求你的MongoDB部署为副本集或分片集群模式,单机模式不支持Change Stream。
方案2:自定义定时任务清理过期Token(兼容单机MongoDB)
如果你使用的是单机MongoDB不支持Change Stream,可以放弃TTL索引的自动过期能力,自行实现定时任务扫描清理过期Token,清理时同步更新关联的Driver文档。
步骤1:修改TokenSchema移除expires配置
const tokenSchema: Schema = new Schema({ token: { type: String, required: true }, // 移除expires属性 creationDate: { type: Date, required: true, default: Date.now }, });
步骤2:添加定时清理任务
以node-cron为例:
import * as cron from 'node-cron'; // 每分钟执行一次清理任务,和原TTL过期周期对齐 cron.schedule('* * * * *', async () => { const oneMinuteAgo = new Date(Date.now() - 60 * 1000); // 查询所有过期的Token const expiredTokens = await Token.find({ creationDate: { $lt: oneMinuteAgo } }); const expiredTokenIds = expiredTokens.map(token => token._id); // 先清空关联Driver的token引用 await Driver.updateMany( { token: { $in: expiredTokenIds } }, { $unset: { token: "" } } ); // 再删除过期Token await Token.deleteMany({ _id: { $in: expiredTokenIds } }); });
内容的提问来源于stack exchange,提问作者Houssem TRABELSI
相关产品推荐
相关产品推荐

