【问题标题】:Create a conditional TTL in mongo在 mongo 中创建条件 TTL
【发布时间】:2016-05-12 17:27:03
【问题描述】:

我想要完成一项特定的任务,但我没有找到任何特定的方法来做到这一点。 假设我有一个用于发送邮件的应用程序。我将这些电子邮件记录在 mongo 的集合中。使用这个应用程序,我可以立即发送邮件,也可以安排将来的电子邮件。 集合中文档的结构如下:

{
'_id' : 123456789,
'to_email' : 'xyz@gmail.com'
'from_email' : 'abc@gmail.com'
'subject': 'some subject'
'type' : '<1 if normal and 2 if scheduled>',
'createdDate' '<date when mail was sent or the request was created>',
'scheduledDate' : '<time for which mail is scheduled>'
.. and many more key-value pairs
}

scheduledDate 字段可以是零或任何日期,具体取决于它是否已安排。 我不想保留超过 2 天的数据,所以我在“createdDate”上创建了一个 TTL 索引 2 天。 但我也不想删除为将来安排的行或请求。 我一直在寻找某种有条件的 TTL,但找不到任何这样的解决方案。

在 MongoDB 中是否有任何可用的方法,例如条件 TTL 或任何其他方式。

我想创建一个 TTL,其工作方式如下:

if(requestType!=2 and createdDate < -2days)
delete row;

或者有什么方法可以让我使用任何语言对某些文档进行更改,以免它们过期。

编辑:我解决了这个问题,在预定电子邮件的情况下使用 scheduledDatecreatedDate 的相同值。

【问题讨论】:

  • 请分享 scheduleDate 的架构类型。我尝试创建类型:Date,默认值:new Date()。因此,如果条目为零,则它将在 5 分钟内被删除,如果条目有日期,则不会被删除。但是在插入之后,我检查而不是像这样使用 ISO (00:00:00-000z) 保存 0 时间格式。我想初始存储 0(数字格式),然后当条件出现时,它将保存当前的 ISO 日期时间戳。这样在特定分钟后只有 0 oen 会删除

标签: mongodb mongodb-query mongodb-indexes


【解决方案1】:

从 MongoDB 3.2 开始,还可以使用指定的过滤器表达式添加部分 TTL 索引。如果您只需要删除正常未安排的电子邮件,您可以使用以下方法:

db.email.createIndex( {createdDate: 1}, {
    expireAfterSeconds: 172800, // 2 days
    partialFilterExpression: {
        scheduledDate: 0
    }
});

请注意,partialFilterExpression 对可能的过滤条件有限制:https://docs.mongodb.com/manual/core/index-partial/

【讨论】:

    【解决方案2】:

    我只想添加另一个字段。数据不多:

    {
    '_id' : 123456789,
    'createdDate' '<date when mail was sent or the request was created>',
    'scheduledDate' : '<time for which mail is scheduled>'
    'expires': '<Date or NULL>'
    }
    

    将 0 秒的 TTL 索引添加到 expires 字段。不要将 TTL 添加到其他日期。

    以下示例在 Mongoose(Node 的 ORM)中,但这些想法应该适用于您使用的任何框架:

    默认值

    您可以将默认值添加到 expires 字段,其值为“创建日期 + 2 天”。

    {
      type: Date,
      default: function() { 
        return new Date(Date.now() + 1000*60*60*24*2);
      }
    }
    

    计划任务的不同到期日期

    只需明确设置日期:

    myNewDocument.expires = new Date( scheduled + ... );
    

    或者更改设置默认值的函数:

    function() {
        if(this.get("type") === 2) {
          return scheduled_date_plus_2_days;
        } else {
          return created_date_plus_2_days;
        }
    }
    

    根本没有过期

    将该字段设置为NULL:

    myNewDocument.expires = null;
    

    这样,您可以为普通邮件、重要邮件、预定邮件等选择不同的到期时间。如果您准时,您甚至可以将expires字段设置为NULL以取消自动删除.
    唯一需要注意的是,如果您更改预定时间,则需要更新 expires 字段。

    【讨论】:

    • 所以你会像(Docs)那样添加使其过期所需的索引? db.emails.createIndex( { "expires": 1 }, { expireAfterSeconds: 0 } )
    • 这对我来说是正确的:在您的情况下,当当前日期是 expires 字段的值时,文档将被删除(给或花一分钟)。
    【解决方案3】:

    您可以在scheduledDate 上创建一个 TTL 索引,如果该值为零,则不会被删除。根据documentation,如果文档中的索引字段不是日期或包含日期值的数组,则文档不会过期。

    使用 Mongo 3.2 我已经验证了使用这个测试集合确实是这种情况:

    db.data.drop()
    db.data.save({scheduledDate: 0})
    db.data.save({scheduledDate: new Date()})
    db.data.save({scheduledDate: new Date()})
    db.data.createIndex( { "scheduledDate": 1 }, { expireAfterSeconds:1} )
    

    使用此集合时,所有 new Date() 条目都将被删除,而第一个为零值的记录仍然存在

    【讨论】:

    • 但是如果为'createdDate'设置了另一个TTL索引,那么它也不会过期吗?
    • 你只想在scheduledDate上添加一个TTL索引,你的想法是只有在记录发送成功后才删除记录,否则看看RikkusRikkus的解决方案,
    【解决方案4】:
    const mongoose = require("mongoose");
    const Schema = mongoose.Schema;
    
    let PassWordReSate = new Schema(
      {
        hex: String,
        email: String,
      },
      {
        collection: "PassWordReSate",
        timestamps: true,
      }
    );
    PassWordReSate.path("createdAt").index({ expires: 6 });
    module.exports = mongoose.model("PassWordReSate", PassWordReSate);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-03
      • 2014-03-12
      • 1970-01-01
      • 1970-01-01
      • 2015-01-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多