Why could the findOrCreate plugin create several documents at once?

Viewed 25

I'm currently working on a MERN application with following/follower function for the users. I decided to create separate schemas for following and follower relationships detached from user schema.

Follower schema

const mongoose = require('mongoose');
const findOrCreate = require('mongoose-findorcreate');
const ObjectId = mongoose.Schema.Types.ObjectId;

const followerSchema = mongoose.Schema({
    userId: {
        type: ObjectId,
        ref: 'User'
    },
    follower: {
        type: [ObjectId],
        ref: 'User'
    }
});

followerSchema.plugin(findOrCreate);

const Follower = mongoose.model('Follower', followerSchema);
module.exports = { followerSchema, Follower };

Following schema

const mongoose = require('mongoose');
const findOrCreate = require('mongoose-findorcreate');
const ObjectId = mongoose.Schema.Types.ObjectId;

const followingSchema = mongoose.Schema({
    userId: {
        type: ObjectId,
        ref: 'User'
    },
    following: {
        type: [ObjectId],
        ref: 'User'
    }
});

followingSchema.plugin(findOrCreate);

const Following = mongoose.model('Following', followingSchema);

module.exports = { followingSchema, Following };

The problem however starts in my service where followings are created as supposed to. However, for followers mongoose create 6-8 documents at once with userIds that don't even exist in my db.

Here's the code of the followerService (it's the first function)

const { Follower } = require('../models/followerModel');
const { Following } = require('../models/followingModel');
const { User } = require('../models/userModel');
const mongoose = require('mongoose');

exports.changeFollowStatus = async (user, userId) => {
    console.log({ userId: userId, user: user._id });
    const newFollowing = await Following.findOrCreate({ userId: user._id }, (err, following, created) => {
        console.log({following: following});
        if (!err && !isFollowing(following, userId)) {
            following.following.push(mongoose.Types.ObjectId(userId));
            following.save();
            User.findByIdAndUpdate(mongoose.Types.ObjectId(userId), {$inc: {follower: 1}});
        } else {
            const followingIndex = following.following.indexOf(mongoose.Types.ObjectId(userId));
            following.following.splice(followingIndex, 1);
            following.save();
            User.findByIdAndUpdate(mongoose.Types.ObjectId(userId), { $inc: { follower: -1 } });
        }
    });
    const newFollower = await Follower.findOrCreate({ userId: mongoose.Types.ObjectId(userId) }, (err, follower, created) => {
        console.log({follower: follower});
        if (!err && !isFollower(follower, user._id)) {
            follower.follower.push(user._id);
            follower.save();
            User.findByIdAndUpdate(user._id, { $inc: { following: 1 } });
        } else {
            const followerIndex = follower.follower.indexOf(user._id);
            follower.follower.splice(followerIndex, 1);
            follower.save();
            User.findByIdAndUpdate(user._id, { $inc: { following: -1 } });
        }
    });
};

exports.showFollowings = async (userId) => {
    const followings = await Following.findOrCreate({ userId: mongoose.Types.ObjectId(userId) });

    return followings.following;
};

exports.showFollowers = async (userId) => {
    const followers = await Follower.findOrCreate({ userId: mongoose.Types.ObjectId(userId) });

    return followers.follower;
};

const isFollowing = (newFollowing, userId) => {
    return newFollowing.following.includes(mongoose.Types.ObjectId(userId));
};

const isFollower = (newFollower, userId) => {
    return newFollower.follower.includes(userId);
}

Now, my following adding code and follower adding code look almost identical, but for some reason for followers, mongoose creates many more documents. The strange thing is that there is a follower document with the correct userId, but many other with random userIds get created which doesn't happen with followings which works as supposed to.

I also checked whether I pass the correct values and everything seems to be fine. But just for reference, here's the controller function from which I pass the values.

exports.changeFollowingStatus = async (req, res, next) => {
    passport.authenticate('jwt', async (err, user, info) => {
        if (err) {
            console.error({ authError: err });
        };
        if (info !== undefined) {
            console.error({ authError: info.message });
            res.status(403).send(info.message);
        } else {
            console.log({params: req.params});
            const userToFollow = req.params.id;
            await FollowerService.changeFollowStatus(user, userToFollow);
            res.status(200).send({ message: 'success' })
        }
    })(req, res, next);
};

Could anyone help me with this bug or at least navigate me towards the right direction? I can't seem to find solution to my problem. Thank you all in advance!

0 Answers
Related