我使用MongoDb和Mongoskin。在一个集合我保存事件。
在其他字段中,这些事件具有开始和结束,在Mongodb中保存为Dates
。
events {
start: "Date1",
end: "Date2",
...
}
在此集合中插入新文档时,我需要一个禁止插入文档的约束,该文档的开始日期与创建的事件重叠。简而言之,我不希望任何事件共享相同的时间跨度。
问题:有没有办法通过某种独特的索引处理MongoDb这个约束?我想不是,但如果我错了,请纠正我!
如果不是:
问题在插入新事件之前,是否必须检查可能的重叠代码?我是否需要设置某种写锁定,以便其他用户在检查重叠和插入自己的事件之间不能挤入事件?如何在MongoDb中完成?
修改
这是我到目前为止提出的最佳方式,它实际上看起来效果还不错。
var input = getPostInput();
var query = {$and: [
{start: {$lte: input.end}},
{end: {$gte: input.start}}
]};
db.events.findAndModify(query, {}, {$setOnInsert: input}, {new: true, upsert: true}, callback)
它使用findAndModify
作为" findOrCreate"的类型。运营商。 $setOnInsert
仅在findAndModify
找不到文档时添加POST输入属性,upsert: true
表示如果找不到文档,则应创建文档。组合这两个选项似乎创建了一个findOrCreate运算符。
修改
更新(PUT)事件时出现问题。我无法重复使用上述代码,因为它依赖于upsert
和$setOnInsert
。
修改
@wdberkeley:
我仍然在努力解决这个主要问题:确保范围内的唯一性。我想的越多,似乎"时间片阵列"可能是最无问题的解决方案。例如,假设选择5分钟作为最小时间段,平均预订时间为45分钟。这需要我保存9个数字(可能是date
s):timespan = [0,5,10,15,20,25,30,35,40]
,而不是两个:start=0, end=45
。
对于平均预订,这超过四倍更多保存的数据。
我不是故意要严厉,但你不认为这是一个问题吗?或者当保存的数据 10倍更大或 100倍更大时,它是否首先成为问题?我确实意识到这也与实际预订的总量相关......
答案 0 :(得分:2)
在MongoDB中执行此操作并不是一种简单易行的方法。我做了一个可能适合你的替代选择。如果您的日期采用不连续的步骤,例如,如果这是针对用户按日或按小时保留对象的预订应用程序,则可以使用唯一索引和多键索引的组合。例如,假设预订是白天。约翰Q保留10月11日至10月14日(含)。这就像今年第281至284天 - 让我们假设它到底是哪一天。将保留字段保存为保留日期的数组
> db.reservations.insert({ "span" : [ 281, 282, 283, 284 ] })
在span
字段上添加唯一索引。
> db.reservations.ensureIndex({ "span" : 1}, { "unique" : 1 })
现在,您无法插入其中任何一天的文档:
> db.reservations.insert({ "span" : [ 279, 280, 281, 282 ] })
// unique key error
这可能对您有所帮助,需要进行一些额外的调整以考虑年份,或者它可能是复合唯一索引的一部分,以使时间跨度独特。 room_id
用于酒店预订。
另一种方法是协调客户端的检查。如果你有多个客户根本不能互相交谈,我想最好的办法就是分享一个"锁定"在数据库中:findAndModify
lock
集合中的文档,用于检查和获取锁。一旦客户端通过更改该文档上的字段来获得锁定,它就可以检查与查询的重叠,然后检查插入是否一切正常,然后通过再次更改锁定文档上的标志来释放锁定。