Hi,
I have a stock document.
{
"_id": "601022171517ee00d48ce6ad",
"caseQuantity": 4,
"unitQuantity": 395,
"totalQuantity": 2000,
"currentQuantity": 1995,
"isClaimActive": "true",
"claim": 32,
"status": "Active",
"purchaseInventoryId":"601022151517ee00d48ce6ac",
"index": "1611670005862",
"batchNo": 1,
"unitPrice": 14.19,
"casePrice": 255.75,
"product": "5f8d9a6184c1d0005814ed61",
"productName": "Red Cow - Red Cow 18g",
"type": "5f8d931fcc42160023d770e2",
"units": 400,
"agency": "5f8d6f0acc42160023d770c4",
"createdBy": "5f8d6f2dcc42160023d770c5",
"__v": 0
}
Imagine that two users are updating the currentQuantity of the above document at the same time.
I have used the below code to run the stock update. (Stock.updateOne)
const { records } = req.body;
const agency: any = req.currentUser!.agency;
let stockItemsNoUpdate: any[] = [];
const promiseArray: Query<any>[] = [];
let recordCounter = -1;
let response = {};
const session = await mongoose.startSession();
session.startTransaction({
readPreference: 'primary',
readConcern: { level: 'local' },
writeConcern: { w: 'majority' },
});
const existingLoadingSheet = await LoadingSheet.findById(
req.params.id
).session(session);
if (!existingLoadingSheet) {
session.endSession();
throw new NotFoundError('Loading Sheet Not Found');
}
if (existingLoadingSheet.get('agency')._id != agency) {
session.endSession();
throw new AccessRestrictedError();
}
const oldLoadingsheetStockValuesArray = [...existingLoadingSheet?.records];
const oldLoadingsheetStockValuesObj = oldLoadingsheetStockValuesArray.reduce(
function (result, item) {
var key = item.stockId;
result[key] = {
loadingCaseCount: item.loadingCaseCount,
loadingUnitCount: item.loadingUnitCount,
loadingTotal: item.loadingTotal,
stockId: item.stockId,
product: item.product,
index: item.index,
batchNo: item.batchNo,
type: item.type,
};
return result;
},
{}
);
try {
existingLoadingSheet.set({ records, isUnloaded: false });
await existingLoadingSheet.save({ session: session });
for (const el of records) {
recordCounter++;
const oldLoadingTotal =
oldLoadingsheetStockValuesObj[el.stockId] != null
? oldLoadingsheetStockValuesObj[el.stockId].loadingTotal
: 0;
const diff_qty = el.loadingTotal - oldLoadingTotal;
if (diff_qty === 0) {
stockItemsNoUpdate.push({
recordIndex: recordCounter,
stockId: el.stockId,
nModified: 1,
});
}
promiseArray.push(
Stock.updateOne(
{
_id: mongoose.Types.ObjectId(el.stockId),
agency,
},
[
{
$set: {
currentQuantity: {
$add: [
'$currentQuantity',
{
$switch: {
branches: [
{
case: { $gt: [diff_qty, 0] },
then: {
$cond: [
{ $gte: ['$currentQuantity', diff_qty] },
-diff_qty,
0,
],
},
},
{
case: { $lt: [diff_qty, 0] },
then: { $abs: diff_qty },
},
],
default: 0,
},
},
],
},
},
},
{
$set: {
unitQuantity: {
$mod: ['$currentQuantity', el.units],
},
},
},
{
$set: {
caseQuantity: {
$floor: {
$divide: ['$currentQuantity', el.units],
},
},
},
},
],
{ session: session }
)
);
}
const promiseResults = await Promise.all(promiseArray);
for (const el of stockItemsNoUpdate) {
promiseResults[el.recordIndex]['nModified'] = 1;
}
recordCounter = -1;
stockItemsNoUpdate = [];
for (const result of promiseResults) {
recordCounter++;
if (result.nModified === 0) {
stockItemsNoUpdate.push(records[recordCounter]);
}
}
if (stockItemsNoUpdate.length > 0) {
await session.abortTransaction();
session.endSession();
response = {
status: 'updateFailed',
data: {
failed: stockItemsNoUpdate,
},
};
return res.status(200).send(response);
}
await session.commitTransaction();
session.endSession();
} catch (error) {
console.log(error);
await session.abortTransaction();
session.endSession();
throw new Error(
`Error occured while trying to update the loading sheet. ${error}`
);
}
response = {
status: 'success',
data: {
sheet: existingLoadingSheet,
},
};
res.send(response);
}
Above code works perfectly and gives me the expected output. This is because i am the only one who is using the document. But My concern is will this avoid any concurrency issues if multiple users start using the same document simultaneously??
Some help would be much appreciated as I am new to MongoDB??