【问题标题】:Mongo TTL not removing documentsMongodb TTL不删除文档
【发布时间】:2016-04-20 13:59:08
【问题描述】:

我正在处理集合中的自动过期文档。 Java 应用程序根据 Mongo TTL 文档创建一个索引。

coll.createIndex(new Document("Expires", 1).append("expireAfterSeconds", 0));

插入文档时,我将Expires 字段设置为未来的Date。对于此测试,我将其设置为未来 1 分钟。

我已验证日期正确存在,索引似乎正确,并且我已经等待了 10 多分钟(即使 ttl 运行器每 60 秒运行一次),但文档仍然存在。

{
    "_id" : ObjectId("569847baf7794c44b8f2f17b"),
    // my data
    "Created" : ISODate("2016-01-15T02:02:30.116Z"),
    "Expires" : ISODate("2016-01-15T02:03:30.922Z")
}

我还能错过什么?以下是索引:

[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "prism.prismEventRecord"
    },
    {
        "v" : 1,
        "key" : {
            "Location.X" : 1,
            "Location.Z" : 1,
            "Location.Y" : 1,
            "Created" : -1
        },
        "name" : "Location.X_1_Location.Z_1_Location.Y_1_Created_-1",
        "ns" : "prism.prismEventRecord"
    },
    {
        "v" : 1,
        "key" : {
            "Created" : -1,
            "EventName" : 1
        },
        "name" : "Created_-1_EventName_1",
        "ns" : "prism.prismEventRecord"
    },
    {
        "v" : 1,
        "key" : {
            "Expires" : 1,
            "expireAfterSeconds" : 0
        },
        "name" : "Expires_1_expireAfterSeconds_0",
        "ns" : "prism.prismEventRecord"
    }
]

【问题讨论】:

  • 你能告诉我们 db.coll.getIndexes() 从 shell 的内容吗?只是想确认索引是否正常。
  • 将结果添加到我的问题中

标签: mongodb


【解决方案1】:

我想知道将 java mongo 客户端从图片中取出一分钟是否有意义。

我创建了一个类似的集合,并在 shell 中进行了以下调用。

db.weblog.createIndex({"expireAt":1},{expireAfterSeconds:0})

当我这样做时,然后我调用 db.weblog.getIndexes(),这就是到期索引的样子:

{
    "v" : 1,
    "key" : {
        "expireAt" : 1
    },
    "name" : "expireAt_1",
    "ns" : "logs.weblog",
    "expireAfterSeconds" : 0
}

我认为您的 java 调用可能是“附加”一个新列到您的索引(而不是设置您希望设置的属性)。 看看...您的索引 def 看起来像这样:

{
    "v" : 1,
    "key" : {
        "Expires" : 1,
        "expireAfterSeconds" : 0
    },
    "name" : "Expires_1_expireAfterSeconds_0",
    "ns" : "prism.prismEventRecord"
}

明白我的意思了吗? "expireAfterSeconds 是一个键,而不是一个属性。 现在 -- 你如何用 java shell 做到这一点?嗯......不要对我大喊大叫,但我是 ac# 家伙......我找到一两个 punt on the question of ttl indexes from the java client 的帖子,但它们已经过时了。

也许 java 客户端已经变得更好并且现在支持选项?希望知道问题出在哪里,让一个拥有出色编码技能的人能够从这里解决问题;-)

编辑:堆栈 java 驱动程序代码(未经测试):

IndexOptions options = new IndexOptions()
    .name('whocareswhatwecallthisindex')
    .expireAfter(1, TimeUnit.DAYS);
coll.createIndex(new Document("Expires", 1), options);

EDIT2:创建相同索引的C#驱动代码:

var optionsIdx = new CreateIndexOptions() { ExpireAfter = new TimeSpan(0)};
await coll.Indexes.CreateOneAsync(Builders<MyObject>.IndexKeys.Ascending("expiresAt"), optionsIdx);

【讨论】:

  • 我还不能测试,但我感觉你是对的 - 这可能是在 Document 对象上使用的 .append 方法的问题。而不是附加我可能应该提供两个完全独立的文档。我很肯定就是这样。
  • 是的。检查似乎在 java 客户端中也可以工作的索引选项类(在答案末尾添加了代码)。 C# 代码有效,但我无法测试 Java 代码。
  • 是的,就是这样。谢谢
【解决方案2】:

如果您作为 Golang 用户遇到这个问题,您有两个选择:

1 使用结构:当您知道有效负载结构并且有大量文档时,此方法有效

2 在您的 JSON 负载中引入一个实际的日期对象:仅当由于某种原因您的负载结构由于某种原因绝对无法提前知道时才使用此对象。

在我的例子中,源数据来自一个结构是黑盒的系统。我首先尝试引入一个符合 ISO 标准的 TTL 索引,它的格式与 Mongo 的格式匹配,但它仍然被读取为文本。这导致我推断这是由于未指示驱动程序正确格式化。

我相信深入研究 Mongo 的 Golang 驱动程序的细节来操纵这个过程只能给我们一个短暂的解决方案(因为实施细节可能会发生变化)。所以相反,我建议在你的有效载荷中引入一个真实的日期属性,并让驱动程序为 Mongo 调整它(将这个 sn-p 中的原理适应你自己的代码结构)

err = json.Unmarshal([]byte (objectJsonString.String()), &objectJson)
if err == nil && objectJson != nil {
        //Must introduce as native or they are considered text
        objectJson["createdAt"] = time.Now()
        //Your other code
        insertResult, err := collection.InsertOne(context.TODO(), objectJson)
}

因此,基本上,通常使用其余数据创建您的 JSON 或 BSON 对象,然后使用实际日期值引入您的 TTL 索引,而不是尝试让您的 JSON 解析器为您完成这项工作。

我期待更正,请保持文明,我将确保根据所提出的任何意见更新和改进此答案。

【讨论】:

    猜你喜欢
    • 2013-09-14
    • 2016-08-03
    • 1970-01-01
    • 2019-09-23
    • 2014-05-05
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多