Home > Back-end >  Update values by removing elements in the array with NodeJs and Mongoose
Update values by removing elements in the array with NodeJs and Mongoose

Time:10-05

The functionality I want to achieve: On the frontend I have the list of all the owners in with checkboxes.. The added owners are already checked.. How can I achive that if I uncheck some owner ID and check like 2 new owners, so I remove the unchecked owner and add the new "checked" one.

I have a user model:

const UserSchema = new mongoose.Schema({
  email: { type: String, required: true, min: 6, max: 255 },
  password: { type: String, required: true, min: 4, max: 1024 },
  role: { type: String, required: true, default: "User" },
  owners: [
    {
      type: Schema.Types.ObjectId,
      ref: "Owners",
      required: false,
    },
  ],
});

Every usser has an array of owners enter image description here

I add owner to the specific user with this query PUT METHOD:

exports.addOwnerToUser = async (req: Request, res: Response) => {
  try {
    let ObjectID = require("mongodb").ObjectID;
    const mongoose = require("mongoose");

    const user = {
      email: req.body.email,
      ownerId: req.body.ownerId,
    };

        const updatedUser = await User.findOneAndUpdate(
  { _id: req.params.userId, owners: { $ne: req.body.ownerId } },
  { $push: { owners: { $each: req.body.ownerId } } },
  { new: true, useFindAndModify: false }
);

    res.status(201).json({ sucess: true, msg: "User updated sucessfully" });
  } catch (err) {
    res.status(404).json(err);
  }
};

2.) How can I achive that, if I on the frontend UNCHECK the owner, that it gets removed from owners array?

CodePudding user response:

You can use $pullAll

This operation removes all instances of the values you set from the scores array

const updatedUser = await User.findOneAndUpdate(
  { _id: req.params.userId, owners: { $ne: req.body.ownerId } },
  { $pullAll: { owners: ["630367b3c8e06afa0339a609"] } },
);

You can read the docs HERE

CodePudding user response:

I solved it like that:

exports.addOwnerToUser = async (req: Request, res: Response) => {
  try {
    let ObjectID = require("mongodb").ObjectID;
    const mongoose = require("mongoose");

    const user = {
      email: req.body.email,
      ownerId: req.body.ownerId,
    };

    const updatedUser = await User.findOneAndUpdate(
      { _id: req.params.userId },
      { $push: { owners: { $each: req.body.ownerId } } },
      { new: true, useFindAndModify: false } */

      { _id: req.params.userId },
      { $set: { owners: req.body.ownerId } },
      { arrayFilters: [{ owners: { $eq: user.ownerId } }], multi: true }
    );

    res.status(201).json({ sucess: true, msg: "User updated sucessfully" });
  } catch (err) {
    res.status(404).json(err);
  }
};

CodePudding user response:

Both the operations $push and $pull are not possible in single property in the update query it will generate a conflict error,

There are 3 options I would suggest,

  1. If owners array has limited to a max of 10 elements then Get the whole array of owners id from the front-end and update that array, so don't require the push and pull operations

  2. Execute 2 separate queries, first for push and the second for pull elements

  3. try update with aggregation pipeline query starting from MongoDB 4.2, let's understand in an example:

Consider a document:

[
  {
    _id: ObjectId("5a934e000102030405000000"),
    owners: [
      ObjectId("5a934e000102030405000000")
    ]
  }
]

Consider input variables:

let _id = "5a934e000102030405000000";
let addOwners = ["5a934e000102030405000001", "5a934e000102030405000002"];
let removeOwners = ["5a934e000102030405000000"];

Let's prepare our query,

  • wrap the update part in an array bracket
  • $filter to iterate loop of owners array nad remove provided id in removeOwners array variable
  • $concatArrays to concat above filtered array after removing the ids, and add addOwners array variable
const updatedUser = await User.findOneAndUpdate(
  { _id: _id },
  [{
    $set: {
      owners: {
        $concatArrays: [
          {
            $filter: {
              input: "$owners",
              cond: { $not: { $in: ["$$this", removeOwners] } }
            }
          },
          addOwners
        ]
      }
    }
  }],
  { new: true }
);

Playground

  • Related