1

我有一个类似的文件:

{
     ...
     "LastAccess" : "2012-09-19T05:47:45.982Z", // Time of last document access
     "Expires" : "2012-09-19T06:47:45.982Z", // Time this document expires
     "MaxAge" : 3600, // Seconds to live
}

我相信完成我想要的唯一安全方法是 FindAndModify,所以我的问题是,我想将LastAccess更新为当前 UTC 时间(这显然很容易),但是我想通过LastAccess +更新Expires MaxAge,其中 MaxAge 可能因文档而异。

简而言之,是否在一个 FindAndModify 调用中更新文档中的字段(在本例中为 Expires),而它依赖于文档上的另一个字段?

4

1 回答 1

1

您不能在更新查询中使用文档中的现有字段。这里有几个选项。

收藏时间:

如果要在文档过期时删除文档,可以使用生存时间收集。在实时集合中,文档会在指定的持续时间后自动删除,这意味着您可以完全消除“Expires”和“MaxAge”字段。

创建生命周期为 30 秒的 TTL 索引:

mongos> db.last.ensureIndex({ "LastAccess" : 1 }, { "expireAfterSeconds" : 30 })

插入我们的文件:

mongos> db.last.insert({ "Value" : "No Expiration" })
mongos> db.last.insert({ "Value" : "Expiration", "LastAccess": new Date() })
mongos> db.last.find()
{ "_id" : ObjectId("505d15ac283b060dbc637ec0"), "Value" : "No Expiration" }
{ "_id" : ObjectId("505d15b1283b060dbc637ec1"), "Value" : "Expiration", "LastAccess" : ISODate("2012-09-22T01:34:41.102Z") }

睡眠 15 秒:

mongos> sleep(15000)
null
mongos> db.last.find()
{ "_id" : ObjectId("505d15ac283b060dbc637ec0"), "Value" : "No Expiration" }
{ "_id" : ObjectId("505d15b1283b060dbc637ec1"), "Value" : "Expiration", "LastAccess" : ISODate("2012-09-22T01:34:41.102Z") }

更新我们的访问时间:

mongos> db.last.update({ "Value" : "Expiration" }, { "$set" : { "LastAccess" : new Date() }})
mongos> sleep(15000)
null

这两个文件仍然存在:

mongos> db.last.find()
{ "_id" : ObjectId("505d15ac283b060dbc637ec0"), "Value" : "No Expiration" }
{ "LastAccess" : ISODate("2012-09-22T01:35:07.629Z"), "Value" : "Expiration", "_id" : ObjectId("505d15b1283b060dbc637ec1") }

睡眠 30 秒:

mongos> sleep(30000)
null

现在只有我们没有过期的文档:

mongos> db.last.find()
{ "_id" : ObjectId("505d15ac283b060dbc637ec0"), "Value" : "No Expiration" }

请注意,删除文档的过程每分钟仅运行一次,因此删除某些内容的时间可能在其实际到期日期之后最多一分钟。

两个查找和修改调用:

插入具有所需值的文档:

mongos> db.last.insert({"Value":"oldvalue","LastAccess":new Date(),"Expires":new Date((new Date()).valueOf() + 3200),"MaxAge":3200,InProgress:false})
mongos> db.last.find()
{ "_id" : ObjectId("505b89292271f63498810600"), "Value" : "oldvalue", "LastAccess" : ISODate("2012-09-20T21:22:49.637Z"), "Expires" : ISODate("2012-09-20T21:22:52.837Z"), "MaxAge" : 3200, "InProgress" : false }

修改 InProgress 字段以警告其他人我们正在查看 MaxAge 字段(如果您不关心在您执行此操作时是否有人更改了 MaxAge 字段,则不需要 InProgress 字段,您只需在这一步):

mongos> doc = db.last.findAndModify({ "query" : { "Value" : "oldvalue", "InProgress" : false }, "update" : { "$set" : { "InProgress" : true } } });
{
    "_id" : ObjectId("505b89292271f63498810600"),
    "Value" : "oldvalue",
    "LastAccess" : ISODate("2012-09-20T21:22:49.637Z"),
    "Expires" : ISODate("2012-09-20T21:22:52.837Z"),
    "MaxAge" : 3200,
    "InProgress" : false
}
mongos> db.last.find()
{ "_id" : ObjectId("505b89292271f63498810600"), "Value" : "oldvalue", "LastAccess" : ISODate("2012-09-20T21:22:49.637Z"), "Expires" : ISODate("2012-09-20T21:22:52.837Z"), "MaxAge" : 3200, "InProgress" : true }

实际上使用新的到期日期更新文档,并将 InProgress 设置为 false 以标记我们不再查看 MaxAge:

mongos> db.last.findAndModify({ "query" : { "Value" : "oldvalue", "InProgress" : true }, "update" : { "$set" : { "Value" : "newvalue", "LastAccess" : new Date(), "Expires" : new Date((new Date()).valueOf() + doc.MaxAge), "InProgress" : false } }, "new" : true });
{
    "_id" : ObjectId("505b89292271f63498810600"),
    "Value" : "newvalue",
    "LastAccess" : ISODate("2012-09-20T21:23:29.058Z"),
    "Expires" : ISODate("2012-09-20T21:23:32.258Z"),
    "MaxAge" : 3200,
    "InProgress" : false
}

db.eval():

db.eval() 也可以在这里使用,但出于性能原因应避免使用

于 2012-09-23T19:17:34.827 回答