MongoDb对Date范围的唯一约束

时间:2014-09-26 09:09:29

标签: javascript mongodb mongoskin

我使用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倍更大时,它是否首先成为问题?我确实意识到这也与实际预订的总量相关......

1 个答案:

答案 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集合中的文档,用于检查和获取锁。一旦客户端通过更改该文档上的字段来获得锁定,它就可以检查与查询的重叠,然后检查插入是否一切正常,然后通过再次更改锁定文档上的标志来释放锁定。

相关问题