MongoDb unique date range restrictions

I am using MongoDb with Mongoskin. In the collection I save events. Among other fields, these events have a start and an end, stored as Dates in Mongodb.

 events { start: "Date1", end: "Date2", ... } 

When inserting new documents into this collection, I need a delimiter that prohibits the insertion of a document, which start dates overlap the created case. In short, I do not want events to have the same time span.

Question: Is there a way to deal with this restriction through MongoDb with some unique index? I think not, but please correct me if I am wrong!

If not:

Question Do I have to check for possible code overlaps before inserting new events? Do I need to configure some kind of write lock so that another user cannot compress the event between the time that I check for overlaps and the input of my own event? How is this done in MongoDb?

EDIT

This is the best way that I have reached so far, in fact it works very well.

 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) 

It uses findAndModify as the type of the findOrCreate statement. $setOnInsert add POST input properties only if findAndModify does not find the document, and upsert: true says that it should create the document if it is not found. The two options in combination seem to create the findOrCreate statement.

EDIT

Problems arise when updating (PUT) events. I cannot reuse the code above because it relies on upsert and $setOnInsert .

EDIT

@wdberkeley:

I am still afraid of this basic problem: to ensure uniqueness in the range . The more I think about it, it seems that an “array of time slices” may be the most problematic solution. For example, suppose that 5 minutes is selected as the minimum time period and the average booking is 45 minutes. This would require me to save 9 numbers (possibly date s): timespan = [0,5,10,15,20,25,30,35,40] instead of two: start=0, end=45 . This is more than four times the stored data for an average reservation. I don’t want to be harsh, but don’t you see this as a problem? Or does it become a problem when the stored data is more than 10 times larger or 100 times larger? I really understand that this also applies to the total number of orders made ...

+1
javascript mongodb mongoskin
Sep 26 '14 at 9:09
source share
1 answer

There is no easy way to do this in MongoDB. I have prepared one alternative that might work for you. If your dates start with discrete steps, for example, if this is a reservation application in which users reserve objects by day or hour, then you can use a combination of unique indexes and multi-indexes. For example, suppose a reservation is in the afternoon. John Q reserves from October 11 to October 14 inclusive. This is something like the 281st - 284th days of the year - let's say that on what days this happens. Save the reservation field as an array of days reserved

 > db.reservations.insert({ "span" : [ 281, 282, 283, 284 ] }) 

Put a unique index in the span field.

 > db.reservations.ensureIndex({ "span" : 1}, { "unique" : 1 }) 

Now you cannot insert a document that has any of these days in its range:

 > db.reservations.insert({ "span" : [ 279, 280, 281, 282 ] }) // unique key error 

This may work for you with some additional tweaking to account for the year, or it may be part of a complex unique index to make time intervals unique, for example. room_id for hotel reservation.

Another way is to simply coordinate client-side checks. If you have several clients that don’t talk to each other at all, I think the best way to do this is to split the “lock” in the database: findAndModify document in the lock collection to check and get the lock. As soon as the client has a lock by changing the field on this document, he can perform a check for overlaps with the request, and then insert, if all is well, then release the lock by changing the flag in the lock document again.

+1
Sep 26 '14 at 15:22
source share