MongoDB FindAndModify依赖于文档字段/值

时间:2012-09-19 17:51:06

标签: mongodb mongodb-.net-driver

我有一个类似的文件:

{
     ...
     "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 + MaxAge 更新过期,其中MaxAge在文档到文档的基础上可能不同。

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

1 个答案:

答案 0 :(得分: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" }

请注意,删除文档的过程只会运行once per minute,因此删除某些内容的时间可能会在实际到期日期后的一分钟内停止。

两个查找和修改调用:

插入包含所需值的文档:

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()也可以在这里使用,但performance reasons

应该避免使用