【问题标题】:MGO TTL indexes creation to selectively delete documentsMGO TTL 索引创建以选择性地删除文档
【发布时间】:2016-04-19 14:00:51
【问题描述】:

我正在使用 Golang 和 MongoDB。我有一个集合,它需要保存一个可以持久或易变的文档。因此,如果它设置了过期日期(例如 expireAt),则该文档被视为易失性并被删除,否则它将保留在集合中,除非它被手动删除。

阅读this doc 我发现了一个可以按我的需要工作的索引。

基本上我需要在mgo中复制这种索引:

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

db.log_events.insert( {
  "expireAt": new Date('July 22, 2013 14:00:00'),
  "logEvent": 2,
  "logMessage": "Success!"
} )

我已阅读(我正在搜索此信息的来源)如果expireAt 不是有效日期,则不会触发删除。因此,我认为我需要做的就是在需要时将 expireDate 设置为有效日期,否则我会将其留给 Go time.Time 零值。

这是我的代码库

type Filter struct {
    Timestamp time.Time     `bson:"createdAt"`
    ExpireAt  time.Time     `bson:"expireAt"`
    Body      string        `bson:"body"`
}

// Create filter from data received via REST API.
var filter Filter
timestamp := time.Now()

if theUserAction == "share" { // This is action will set the document as volatile
    filter.ExpireAt = time.Now().Add(24 * time.Hour * 14)
}

filter.Timestamp = timestamp
filter.Body = "A BODY"

// Store filter in database
session, err := mdb.GetMgoSession() // This is a wrapping method that returns a valid mgo session
if err != nil {
    return NewErrorInternal("Error connecting to database", err)
}
defer session.Close()


// Get db with global data for legent
collection := session.DB(database).C(filtersCollection)

我的问题是:如果expireAt 键有效,我如何设置索引以便删除文档? 阅读mgo documentation about Index Type 似乎没有办法复制前面提到的索引,因为库只提供ExpireAfter 字段..

另外,假设 mongodb 可以将零值解释为无效日期是否有效?

从文档中看,它是 January 1, year 1, 00:00:00.000000000 UTC,实际上似乎是一个有效的日期..

到目前为止我的想法是做这样的事情:

filtIdx := mgo.Index{
    Key:        []string{"expireAt"},
    Unique:     false,
    Background: true,
    Sparse:     false,
    ExpireAfter: 0,
}

【问题讨论】:

  • 我可能是错的,但我认为 expireAfterSeconds: 0 实际上会被 0 值忽略,因为我“相信”它需要是一个正值.无论如何,TTL 清理过程最多每分钟运行一次,因此任何少于 60 秒的到期时间将至少延长一分钟。至于其余的,我并不是说你“不能”这样做,但你可能想重新考虑在 Go 代码中定义索引的实用性。索引只需要定义一次,因此最好在“部署脚本”中实现,而不是作为通用代码的一部分。
  • 当您希望索引在另一个日期键上过期时,文档本身指定您使用expireAfterSeconds: 0。至于索引是在哪里创建的,是的,你说得对,它现在实际上是在部署脚本中。
  • 你为什么认为你在告诉我一些关于文档的事情?这根本不是它所说的,您可以使用的“唯一”键是索引中指定的“奇异”数据。而“那个”正是文档所说的。老实说,每条评论都有指向用户个人资料的链接。如果你花一点时间看,那么你可能会明白,你要“通知”的人比你自己的概念要好得多,因此是在“给你一些好的建议”。
  • 除了我真正理解的阅读内容之外,我并不想告诉你一些事情,我并没有试图通知你任何事情(我在回复之前也查看了你的个人资料)并且我'对不起,如果我表达自己的方式不好。
  • the "only" key you can use is the "singular" data specified in the index是指mgo Index.Key还是ExpireAfter

标签: mongodb go mgo ttl mongodb-indexes


【解决方案1】:

如果 expireAt 键有效,我如何设置索引以便删除文档?

使用mgo.v2设置TTL索引的示例如下:

index := mgo.Index{
    Key:         []string{"expireAt"},
    ExpireAfter: time.Second * 120, 
}
err = coll.EnsureIndex(index)

上面的示例设置为 120 秒的过期时间。另见Expire Data from Collections by Setting TTL

是否仍然可以使某些文件完全不过期?由于这是我期待的行为,因此我期待获得一个集合,其中一些文档确实过期而其他文档保持持久性

您可以为ExpireAt struct 字段指定omitempty 标志,如下所示:

type Filter struct {
    Timestamp time.Time `bson:"createdAt"`
    Body      string    `bson:"body"`
    ExpireAt  time.Time `bson:"expireAt,omitempty"`
}

本质上只包含未设置为零值的字段。查看更多信息mgo.v2 bson.Marshal

现在,例如,您可以插入两个文档,其中一个将过期而另一个将持续存在。代码示例:

var foo Filter
foo.Timestamp = timestamp
foo.Body = "Will be deleted per TTL index"
foo.ExpireAt = time.Now()
collection.Insert(foo)

var bar Filter
bar.Timestamp = timestamp
bar.Body = "Persists until expireAt value is set"
collection.Insert(bar)

稍后,您可以将expireAt 字段设置为Update(),例如:

newValue := bson.M{"$set": bson.M{"expireAt": time.Now()}}
err = collection.Update(queryFilter, newValue)

expireAt 字段设置一个有效的时间值,将使其符合 TTL 索引。即不再持续存在。

根据您的用例,或者您也可以Remove() 文档,而不是更新和依赖 TTL 索引。

【讨论】:

  • 谢谢@Wan 的回答,自从我遇到这个问题以来已经过去了一年多,所以现在我无法测试它来验证解决方案;无论如何,它似乎是完美的。我没有想到 Gob omitempty 关键字。问题是它避免了插入 0 值时间导致该文档的索引“停用”。我做对了吗?现在我赞成答案,我会尽快测试它以接受它! :)
猜你喜欢
  • 2016-08-03
  • 2014-05-05
  • 2019-09-23
  • 2013-09-14
  • 2016-04-20
  • 2016-03-22
  • 2015-01-09
  • 1970-01-01
相关资源
最近更新 更多