Parallel requests read and write on same document using aggregation

Hello fellow mongodb community,

I have two collections named installmentPromoUsers and installmentPromos . installmentPromoUsers collection stored data about users and the eligibility for each promo, here is the sample data

{
  "_id": {
    "$oid": "66a87013018edd61a7355042"
  },
  "cif": "1AH3CU",
  "promotionIds": [
    "SEGMENT_A_TEST",
    "SEGMENT_B"
  ],
  "usedInstallmentIds": []
}

installmentPromos collection stored information related to promotion details, here is the sample data

{
  "_id": {
    "$oid": "66a1c0854784fc46ec8727a2"
  },
  "installmentId": "RMDHN_3M",
  "availableQuota": 3,
  "expiryDate": {
    "$date": "2025-08-07T08:19:21.000Z"
  },
  "interestRate": "1",
  "minAmount": 500000,
  "name": {
    "en": "3 months",
    "id": "3 bulan"
  },
  "normalRate": 21,
  "promoTitle": {
    "en": "Ramadhan Promo",
    "id": "Promo Ramadhan"
  },
  "promotionId": "SEGMENT_A",
  "quotaCustomer": 5,
  "quotaTotal": 40,
  "startDate": {
    "$date": "2024-07-22T17:00:00.000Z"
  },
  "summary": {
    "en": "- min. 500k\n- min 3 months",
    "id": "- min. 500k\n- min 3 bulan"
  },
  "tenure": 3,
  "termsAndConditions": {
    "en": "- min. 500k\n- min 3 months",
    "id": "- min. 500k\n- min 3 bulan"
  },
  "promotionName": "Ramadhan Promo"
}

In order to get the eligible promotions for particular user along with its detail , i need to join the two collection using aggregation lookup. Also, i need to perform aggregation with lookup and set to update availableQuota and usedInstallmentIds when user use the promotion. Let’s say, there are 5 parallel request to database, 3 of them are reading the date stored in collection installmentPromoUsers and installmentPromos, and 2 of them are updating the date stored in collection installmentPromoUsers and installmentPromos. The questions are :

  1. Does the mongodb block the read request of those 3 clients until the 2 clients finishes update data?
  2. Do i need certain locking mechanism to preserve data consistency for multiple read and write parallel requests?

Thank you

1 Like
  1. Does MongoDB block the read requests of those 3 clients until the 2 clients finish updating data?

No, MongoDB does not block read requests while write operations are in progress. MongoDB uses multi-version concurrency control (MVCC) system, which allows reads and writes to occur concurrently in most cases. Here’s how it basically works:

  • For read operations, MongoDB provides a view of the data at the time the read operation begins… even if a write operation is in progress, read operations will see the data as it was before the write started.
  • Write operations acquire locks to ensure data consistency, but these locks don’t block read operations, afaik.
  1. Do I need a certain locking mechanism to preserve data consistency for multiple read and write parallel requests?

In most cases, you don’t need to implement additional locking mechanisms yourself. MongoDB’s built-in concurrency control is designed to handle multiple concurrent read and write operations. A few things to keep in mind tho…

a) Write Concerns: Ensure you’re using appropriate write concerns for your update operations. This helps ensure that writes are properly propagated before subsequent reads.

b) Read Concerns: If you need the most up-to-date data in your read operations, you might want to use a higher read concern level, such as “majority”.

c) Atomic Operations: For updating the availableQuota and usedInstallmentIds, consider using atomic update operations to ensure consistency. For example:

db.installmentPromos.updateOne(
  { installmentId: "RMDHN_3M" },
  { $inc: { availableQuota: -1 } }
)

db.installmentPromoUsers.updateOne(
  { cif: "1AH3CU" },
  { $push: { usedInstallmentIds: "RMDHN_3M" } }
)

d) Transactions: If you need to update both collections atomically (i.e., either both updates succeed or both fail), consider using multi-document transactions. This ensures that the updates to both collections are treated as a single, atomic operation.

const session = db.client.startSession();
session.startTransaction();

try {
  await db.installmentPromos.updateOne(
    { installmentId: "RMDHN_3M" },
    { $inc: { availableQuota: -1 } },
    { session }
  );
  
  await db.installmentPromoUsers.updateOne(
    { cif: "1AH3CU" },
    { $push: { usedInstallmentIds: "RMDHN_3M" } },
    { session }
  );

  await session.commitTransaction();
} catch (error) {
  await session.abortTransaction();
  throw error;
} finally {
  session.endSession();
}

e) Optimistic Concurrency Control: If you’re concerned about conflicts between parallel write operations, you can implement optimistic concurrency control. This involves checking if the document has been modified since you last read it before applying your updates.

Hope this helps!

2 Likes

thanks for the detailed explanations :slight_smile:

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.