findByIdAndUpdate will delete previous existing data. [MERN]

Good morning all,
First time posting on this forum, I hope that I am not asking an existing question… (personally couldn’t find any similar case).
So I’m using the MERN stack to build a dashboard, a fleet management dashboard. I currently have have two Models. Company and Driver model and I am referencing the Driver Model to the Company. (I did not choose to embed because the application might scale to thousands of drivers, and I saw that in such case better to normalize).

Every time I create a new driver for a specific company, I retrieve the driver’s ID and update the Company document with that ID in order to reference it. It works fine, however, I am using react states to create an array of drivers ID and then pass it to my api call in order to reference all the drivers i’ve added. But states get reset at each page reload or each time I connect from an other device, which is great because I make sure that sensitive data are never stored on the browser for ever.

However I’ve noticed that findByIdAndUpdate will take the data of the current state session and overwrite what’s already in the DB. I would like to instead, push each new session state to the existing array of ObjectID in my mongodb document.

On the net I found $push and $addToSet could help me achieve this but I am obviously doing something wrong that does not make it work.

This is the company schema :

const companyUserModelSchema = new mongoose.Schema({
  companyName: {
    type: String,
    required: [true, 'You must provide a Company Name'],
    unique: true,
    trim: true,
  },
  companyPicture: {
    type: String,
    default: 'default.jpg',
  },
  adminName: {
    type: String,
    required: [true, 'You must provide an Admin for the Company'],
    unique: true,
    trim: true,
  },
  role: {
    type: String,
    enum: ['admin', 'watcher', 'dev'],
    default: 'admin',
  },

  email: {
    type: String,
    required: [true, 'Please provide an Email'],
    unique: true,
    lowercase: true,
    validate: [validator.isEmail, 'Please provide a valide email'],
  },
  password: {
    type: String,
    required: [true, 'Please provide a password'],
    minlength: 8,
    select: false,
  },
  passwordConfirm: {
    type: String,
    required: [true, 'Please confirm your password'],
    validate: {
      //Will only work on SAVE and CREATE
      validator: function (el) {
        return el === this.password;
      },
      message: 'Password are not the same.',
    },
  },
  drivers: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'Driver',
    },
  ],
  passwordChangedAt: Date,
  passwordResetToken: String,
  passwordResetExpires: Date,
  active: {
    type: Boolean,
    default: true,
    select: false,
  },
});

And that’s the controller to update the company document (the one that works but does not behave like I want it to behave, well it does but not for the “drivers” field) :

exports.updateMe = catchAsync(async (req, res, next) => {
  // 1) Create error if user POSTs password data
  if (req.body.password || req.body.passwordConfirm) {
    return next(
      new AppError(
        'This route is not for password updates. Please use /updateMyPassword.',
        400
      )
    );
  }

  // 2) Filtered out unwanted fields names that are not allowed to be updated
  const filteredBody = filterObj(
    req.body,
    'companyPicture',
    'adminName',
    'email',
    'drivers'
  );
  console.log(filteredBody);

  // 3) Update user document
  const updatedUser = await CompanyUser.findByIdAndUpdate(
    req.user.id,
    filteredBody,
    {
      new: true,
      runValidators: true,
    }
  );

  res.status(200).json({
    status: 'success',
    data: {
      user: updatedUser,
    },
  });
});

And this is what I tried to do after my online research, and just simply does not work :

exports.updateDrivers = catchAsync(async (req, res, next) => {
  // 1) Create error if user POSTs password data
  if (req.body.password || req.body.passwordConfirm) {
    return next(
      new AppError(
        'This route is not for password updates. Please use /updateMyPassword.',
        400
      )
    );
  }

  // 2) Update user document
  const addedDriver = await CompanyUser.findByIdAndUpdate(
    req.user.id,
    { $addToSet: { drivers: req.body } },
    {
      runValidators: true,
    }
  );

  res.status(200).json({
    status: 'success',
    data: {
      user: addedDriver,
    },
  });
});

This is not a personal project, but actually my first big order from a real client, and I have to do a demo on Friday, I’m done with everything else, just left with that small issue, I really hope that someone will be able to help me before that, I really have the feeling that I’m being stupid and that I’m just missing something silly to add to my code…

I am already truly grateful and thankful.
Jonathan!

Problem Solved! It was the way I was sending my data from the frontend…

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.