I am designing a social API system where users can follow and unfollow each other. Currently, I have a user model that looks like this:
sourceId: {
type: Schema.Types.ObjectId,
ref: "user",
required: true,
},
targetId: {
type: Schema.Types.ObjectId,
ref: "user",
required: true,
},
approved: {
type: Boolean,
required: true,
default: true,
},
};
When someone follows another user in the system, I am doing something like this:
const query: any = {
targetId: <some_oid>,
sourceId: <some_oid>,
approved: true
};
await new FollowModel(query).save();
await UserModel.updateOne({ _id: targetId }, { $inc: { followerCount: 1 } });
await UserModel.updateOne({ _id: sourceId }, { $inc: { followingCount: 1 } });
sendSuccess(res, FollowStatus.FOLLOWING);
As you can see, the process is pretty simple. Insert to follow model, increase the following count of the person who sent the request and increase the follower count of the person who is being followed.
But there is a lot of things that could go wrong here, like the insert to follow model succeeded and the follower count got updated, but the updation of following count of the source user failed. I do understand that there is MongoDB transactions that could help with this case, but it looks like they cannot work without replica sets and some complex setup process. Is it even possible to achieve a reliable counting solution in this kind of a simple setup? If so, how? How do large social systems handle this?
If a detailed version of the code required for a solution, the full API file is here: https://github.com/shrihari-prakash/liquid/blob/main/src/service/api/user/follow.post.ts