Ali Yousuf
Ali Yousuf

Reputation: 702

Mongo Database Design

I'm designing a website where people can book for events. The schema that I have designed, has some concurrency issues. Let me show the schema first:

{
  title: String,
  pricing: { [
    data: Date,
    package: String,
    price: Number
  ] },
  availability: { [
    date: Date,
    capacity: Number, // Number of users a vendor can take.
    booked: Number // Number of users booked the event for the date.
  ] }
}

Now an event's prices are unique by Date and Package. So a same date can have multiple prices if the package is different.

And the availability is unique by Date only. So I have to create a separate object for that.

Problem

The problem is, I have two different calls.

  1. Save Availability (saves capacity for all dates at once. it's a delete all and insert new type call, but keep the value of booked the same)
  2. Make a booking (increases booked by 1 for a particular date)

Since both resides in the same object, I think I will have a big concurrency issue in future because, if I save availability and at the same time users books the same event, the booked number might not be correct.

Is there a better solution?

Upvotes: 1

Views: 123

Answers (1)

ThrowsException
ThrowsException

Reputation: 2636

I'm assuming your post to update capacity from the client is something like

{
  id: ObjectId //Your event Id
  updates [
      {date: Date, capacity: newCapacity}, 
      {date: Date, capacity: newCapacity}
  ]   
}

You could keep the arrays how they currently are but you should be trying to target just the capacity property instead of overwriting the whole document. The query below will iterate through the post and update the availablity array targeting just the first item in the array that matches the query. I'm assuming javascript as the backend here but the idea is the same. If you have a lot of updates I would look into using bulkUpdate for performance

for(var i = 0; i < updates.length; i++) {
    var update = updates[i];
    db.collection.update(
        {
          _id: update.id, 
          "availability.date": update.date
        }, 
        {$set: {"availability.$.capacity": update.capacity}}
    )
}

for updating booked

for(var i = 0; i < updates.length; i++) {
        var update = updates[i];
        db.collection.update(
            {
              _id: update.id, 
              "availability.date": update.date
            }, 
            {"availability.$.booked": {$inc : 1}}
        )
    }

EDIT Example using bulk operation

var bulk = db.collection.initializeUnorderedBulkOp();
for(var i = 0; i < updates.length; i++) {
    var update = updates[i];
    bulk.find(
        {
          _id: update.id, 
          "availability.date": update.date
        }).update({$set: {"availability.$.capacity": update.capacity}})
    )
}
bulk.execute();

Upvotes: 1

Related Questions