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
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,
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 operationsExecute 2 separate queries, first for push and the second for pull elements
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 ofowners
array nad remove provided id inremoveOwners
array variable$concatArrays
to concat above filtered array after removing the ids, and addaddOwners
array variable
const updatedUser = await User.findOneAndUpdate(
{ _id: _id },
[{
$set: {
owners: {
$concatArrays: [
{
$filter: {
input: "$owners",
cond: { $not: { $in: ["$$this", removeOwners] } }
}
},
addOwners
]
}
}
}],
{ new: true }
);