Javascript MongoDb对日期范围的唯一约束

Javascript MongoDb对日期范围的唯一约束,javascript,mongodb,mongoskin,Javascript,Mongodb,Mongoskin,我使用MongoDb和Mongoskin。在一个集合中,我正在保存事件。 在其他字段中,这些事件有开始和结束,在Mongodb中保存为Dates events { start: "Date1", end: "Date2", ... } 在这个集合中插入新文档时,我需要一个约束,禁止插入开始-结束日期与实际创建的事件重叠的文档。简而言之,我不希望任何事件共享相同的时间跨度 问题:有没有一种方法可以通过MongoDb使用某种唯一索引来处理此约束?我想没有,但如果我错了,请纠正我 如果

我使用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
仅当
find和modify
未找到文档时添加POST输入属性,并且
upsert:true
表示如果未找到文档,则应创建文档。这两个选项的组合似乎创建了一个findOrCreate操作符

编辑

更新(放置)事件时出现问题。我无法重用上面的代码,因为它依赖于
upsert
$setOnInsert

编辑

@伯克利:

我仍在努力解决这个主要问题:确保某个范围内的唯一性。我越想,似乎“时间片数组”可能是最无问题的解决方案。例如,假设选择5分钟作为最小时间段,平均预订时间为45分钟。这需要我保存9个数字(可能是
date
s):
timespan=[0,5,10,15,20,25,30,35,40]
,而不是两个:
start=0,end=45
。 这是平均预订保存数据的四倍多。
我不想说得太苛刻,但你不觉得这是个问题吗?或者,当保存的数据大于10倍或大于100倍时,是否会首先出现问题?我确实意识到,这也与实际预订的总金额有关

在MongoDB中没有一种非常简单的方法可以做到这一点。我想出了一个对你有用的备选方案。如果您的日期是以离散的步骤出现的,例如如果这是一个预订应用程序,其中用户按天或小时预订对象,那么您可以使用唯一索引和多键索引的组合。例如,假设预订是按日进行的。约翰Q保留10月11日至10月14日(含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\u id


另一种方法就是在客户端协调检查。如果您有多个客户端彼此根本不通信,我想最好的方法是在数据库中共享一个“锁”:
find并修改
lock
集合中的文档以检查和获取锁。一旦客户机通过更改文档上的字段而获得了锁,它就可以检查与查询的重叠,然后执行插入操作(如果一切正常),然后通过再次更改锁文档上的标志来释放锁。

感谢您的回复!请阅读我对上述问题的编辑,看看我的解决方案是否是你在上一段中的意思。关于“锁定”,我不知道这是什么意思,但据我所知,这个
findAndModify
将自动完成,因此“锁定”集合,以便其他用户无法在
findAndModify
操作的查询和更新阶段之间的事件中清除。对吗?假设我对整个集合设置了一个锁,当第一个用户拥有锁时,第二个用户正试图保存一个事件。我该如何回应第二个用户?带有错误消息?如果您正在放置已创建的事件,您的解决方案有什么问题?我以为你不想允许重叠?你也可以有一个单独的更新路径。对于第二个用户的锁,您可能会有一个重试循环,但我认为您更简单的解决方案应该可以工作,所以这并不重要。我不希望允许重叠=)。我的解决方案在创建新事件时有效,但在更新已创建事件的时间时无效。我使用findAndModify的方式在更新中不起作用,因为我使用findAndModify的方式仅依赖于创建新文档。看起来我需要某种锁,或者你看到了一些我不知道的更新解决方案吗?请记住,在更新时,我还需要检查时间是否重叠。如果您正在更新已存在的文档,请使用
\u id
参考进行更新。具体的细节取决于应用程序端的更新情况。我一直在研究这个问题,我认为这是最好的解决方案。只要将索引字段中的值数量保持在合理的大小(例如,每个文档不超过数千个),就应该可以正常工作。我猜mongo内部对于如何唯一地索引整数数组非常有效。