Our app requires us of duplicating data accross multiple collection. Our schema looks like the following:
We have participants collection, where participants of an event is stored, then we have two collection accreditationItems and accreditation groups. These two collections stores information about the accreditation that participants can have. Manay participants can have many accreditations.
Because we duplicated accreditation data on multiple participants. When updating accreditation info we need to update participants documents:
We have implemented the following code to do that, (Note we are using mongoose):
import { withTransaction } from "@/db/mongodb";
import accreditationGroupModel from "@/models/accreditationGroup";
import accreditationItemsModel from "@/models/accreditationItems";
import participantModel from "@/models/participant";
interface ReqUser {
id: string;
dbID: string;
eventID: string;
}
interface UpdateData {
_id: string;
name: string;
type: string;
alias: string;
description: string;
color: string;
char: string;
}
export async function Update(user: ReqUser, data: UpdateData) {
await withTransaction(async (session) => {
if (data.type === "category") {
await accreditationGroupModel.updateOne(
{
_id: data._id,
eventID: user.eventID,
},
{
$set: {
name: data.name,
alias: data.alias,
description: data.description,
color: data.color,
char: data.char,
modifiedByID: user.id,
_id: data._id,
},
},
{
session,
}
);
await participantModel.updateMany(
{
"accreditations.accreditationGroupId": data._id,
eventID: user.eventID,
},
{
$set: {
"accreditations.$[i].name": data.name,
"accreditations.$[i].alias": data.alias,
"accreditations.$[i].description": data.description,
"accreditations.$[i].color": data.color,
"accreditations.$[i].char": data.char,
},
},
{
arrayFilters: [
{
"i.accreditationGroupId": data._id,
},
],
session,
}
);
} else {
await accreditationItemsModel.updateOne(
{
_id: data._id,
eventID: user.eventID,
},
{
$set: {
name: data.name,
type: data.type,
alias: data.alias,
description: data.description,
color: data.color,
char: data.char,
modifiedByID: user.id,
},
},
{
session,
}
);
await participantModel.updateMany(
{
"accreditations.items._id": data._id,
eventID: user.eventID,
},
{
$set: {
"accreditations.$[].items.$[j].name": data.name,
"accreditations.$[].items.$[j].alias": data.alias,
"accreditations.$[].items.$[j].description": data.description,
"accreditations.$[].items.$[j].color": data.color,
"accreditations.$[].items.$[j].char": data.char,
},
},
{
arrayFilters: [{ "j._id": data._id }],
session,
}
);
await participantModel.updateMany(
{
"accreditations.usersChanges._id": data._id,
eventID: user.eventID,
},
{
$set: {
"accreditations.$[].usersChanges.$[l].name": data.name,
"accreditations.$[].usersChanges.$[l].alias": data.alias,
"accreditations.$[].usersChanges.$[l].description":
data.description,
"accreditations.$[].usersChanges.$[l].color": data.color,
"accreditations.$[].usersChanges.$[l].char": data.char,
},
},
{
arrayFilters: [{ "l._id": data._id }],
session,
}
);
}
});
}
With the withTransaction is defined in the following way:
import { connect } from "mongoose";
export const conn = connect("mongodb://localhost:27017/test", {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
useCreateIndex: true,
});
async function withTransaction(func: (session: any) => void) {
const session = await conn.startSession();
try {
await session.startTransaction();
await func(session);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
throw error;
}
}
Most of the times this works perfectly, and all data get updated. But sometimes, when running the update, we inconsistence issue. Where some documents are being updated and others not.
We are using Mongodb Atlas version 5,
We are using mongoose as our Nodejs driver.