-1

Bit of background, I have an express backend for my application that is using MongoDB as a database. Auth0 is there as an identity provider.

I have an addTeamUser async function that:

  1. Validates the request body with Joi
  2. Takes an email from the request body
  3. Creates a user in the Auth0 database
  4. When successful, construct a user object with the auth0 id and email
  5. Push that user into an array of users in my local database using mongoose's findOneAndUpdate

The code is as shown below:

const addTeamUser = async (req) => {
  // Get team_id from JWT token
  const team_id = req.auth.team_id;
  const data = req.body;
  // Joi validation for the email body
  const { error } = schema.user.validate(data, { abortEarly: false });

  if (error) {
    return { message: error.message, statusCode: 400 };
  }

  try {
    // Call auth0 management API and create new user with the email provided and custom team_id in app_metadata
    const createdUser = await managementAPI.createUser({
      email: data.email,
      connection: 'Username-Password-Authentication',
      password: "changeme",
      app_metadata: {
        team_id: team_id,
      },
    });

    // Add user to local database if Management API returned a success
    const user = {
      id: createdUser.user_id,
      email: createdUser.email
    };

    const doc = await Team.findOneAndUpdate(
      { team_id },
      { $push: { users: user } },
      { new: true });

    return {
      statusCode: 201,
      users: doc.users,
      message: "User added successfully"
    }

  } catch (err) {
    console.error('Error creating user:', err);
    return { message: 'An error occurred, try again later', statusCode: 500 };
  }
};

Now this works like a charm... except that when the user is inserted in the local database, it sometimes inserts it twice and I end up with two of the same users in my array.

I've done a bit of reading and apparently I can't use await and callbacks at the same time but whatever I do to try to fix it, it will execute it twice.

Here's my Team Schema for more context:

const teamSchema = new Schema({
  team_id: {
    type: String,
    required: true
  },
  name: {
    type: String,
    required: true,
    trim: true,
  },
  users: [
    {
      id: {
        type: String,
        unique: true,
        required: true,
        trim: true
      },
      email: {
        type: String,
        unique: true,
        required: true,
        trim: true
      }
    }
  ],
}, {
  _id: false // This disables the automatic _id field for subdocuments
});

Please let me know what's going on with this bug and how do I fix it?

Crashie
  • 19
  • 6

1 Answers1

0

The reason the findOneAndUpdate method inserts the user two times in because of the {new:true} flag. So removing it will fix your problem. For more info check this previous question:

Document is inserted twice into MongoDB when using Mongoose create method

PTsag
  • 108
  • 2
  • 9
  • I've removed the {new: true} flag and the issue is still there. I've also made sure that the function isn't being made more than once, and tbh even if the function is called twice, the auth0 call would trigger the catch. – Crashie Apr 15 '23 at 11:43
  • I did some search and I found that the await is some times causing this trouble. Remove the `await` from `await managementAPI.createUser` and use the .then() and .catch() for the return. Lastly add back the `{new:true}`. – PTsag Apr 15 '23 at 12:11
  • 1
    Hey, so I ended up using the $addToSet operator instead of $push as I found out it inherently doesn't allow duplicates. Thanks for taking the time to answer <3 – Crashie Apr 15 '23 at 17:36