delete object from document array in mongodb collection using mongoose - javascript

I try to remove an element from an array attribute of my object.
This is my schema :
const userSchema = new mongoose.Schema({
userID: {
type: Number
},
name: {
type: String
},
names: [
{
text: { type: String, required: true },
order: {
type: Number,
required: true
}
}
]
});
this is my mongoose function :
User.findOne({ userID: Number(req.params.id) })
.then((user) => {
user.names.remove({text: "john", order: 3});
recipe.save(() => {
res.json(recipe);
});
})
I don't understand why it's not good :/

As per documentation of mongoose remove method remove operation is only executed when a callback is passed. To force execution without a callback, you must first call remove() and then execute it by using the exec() method.
Since you are trying to delete from array of objects then better would be to use pull operator. You don't have to do find and remove, you can simply use update method.
As per documentation of $pull operator you can either specify a value or a condition
i.e.
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
In your scenario you need to either specify complete value of one or more names item object or an condition that matches one or more names item
Add the condition where you match id of names item or if you don't know that then you can use elemMatch to match on few fields i.e.
Use following pull condition to solve the issue:
User.update(
{ _id: Number(req.params.id) },
{ $pull: { 'names': { $elemMatch: { 'text': "john", 'order': 3 }} } },
(error, success) => {
if (error) console.log(error);
console.log(success);
}
);

To Remove Element from array in document please follow as below
User.update(
{
userID: Number(req.params.id),
},
{
$pull: { names: { $elemMatch: { text: "john", order: 3 } } }
},
{
multi: false
}
).lean().then((Status) => {
console.log("Status-->", Status);
res.json('Removed Successfully');
})
Refer $pull operator at link

Related

UpdateOne MongoDB with push using value from another field

I'm trying to push an existing field of my document to my array. this is my schema :
var mySchema = new Schema({
level: {
type: Number,
default: 1
},
mHierarchy: [
{
userId: {
type: mongoose.Types.ObjectId
},
index: {
type: Number
}
}
]
})
i'm trying to use UpdateOne and push to mHierarchy and set outer level to the index.
what I've tried so far:
MySchema.updateOne(
{'_id': mySchemaId},
$push: {
referredHierarchy: {
userId: mongoose.Types.ObjectId(id),
index: '$$level'
}
}
)}
I also tried this:
let setQuery= {}
setQuery['mHierarchy.' + level + '.userId']= mongoose.Types.ObjectId(userId)
setQuery['mHierarchy.' + level + '.index']= '$$temp'
MySchema.updateOne(
{'_id': mySchemaId},
{
$set: setQuery
},
{let: {temp: '$level'}}
)
and none of the above works and I get this error :
"CastError: Cast to Number failed for value \"$$temp\" (type string) at path \"index\""
how can I achieve this using mongoose?
NOTE: I use MongoDB 5 and "mongoose": 6.0.8
You will need first to add this field to the pipeline with the $set operator. Try this one:
MySchema.updateOne({ _id: mySchemaId }, {
$set: {
index: "$level",
}},{
$push: {
referredHierarchy: {
userId: mongoose.Types.ObjectId(id),
index: "$index",
},
}});
Try another workaround for test reasons:
MySchema.updateMany({ _id: mySchemaId },[{
$addFields: {
index: "$level",
}},{
$push: {
referredHierarchy: {
index: "$index",
},
}}]);
updateOne doesn't accept pipeline aggregation operators so try with this updateMany for testing.

Mongodb, Delete one object from an array of objects using javascript

I am trying to remove one object from an array of my collection, which looks like this. It s a collection in Mongodb
Before deleting a specific object based on chartId, I need to check the userId and the name of the array. Then I need to delete the object.
I have written this code, but its not working. someone will tell me what exactly I am missing in this code.
delChartObj.updateOne(
{ 'userId': userId },
{ $pull: { "Color": { "chartId": req_chart_id } } },
{ safe: true, multi: true}, function (err, obj) {
if (err) { res.send.err }
res.status(200).send({ msg: "Deleted Sucessfully" });
});
In my case, userId = ADAM, array = "Color" and chartID = time
I am using mongoose for performing action
delChartObj is an object of model
const UserSchema = mongoose.Schema({
userId: { type: String, required: true, unique: true },
charts: { type: Object },
});
You should do findOneAndUpdate, the syntax will be something like:
Model.findOneAndUpdate(
< condition>,
{ $pull: { "Color.$.chartId": req_chart_id } } }, // The actual Query
{ new: true }
)
try this in pull
{ $pull: { "Chart.Color.$.chartId": req_chart_id } } },

Using findById to find the id of a schema in an array

Hey I was wondering how do I use findById for a schema inside an array? For example, I have the following Schema:
const GameSchema = new mongoose.Schema({
users: [
{
user: { type: mongoose.Schema.ObjectId, ref: 'User' },
role: {
type: String,
required: true,
enum: ['user', 'moderator', 'creator'],
default: 'user',
},
},
]
}]
I want to find the user with a mongoose function like findById, such as the following:
const user = await game.users.findById({ user: req.user.id })
It doesn't seem to work since users is not a mongodb model. I know I can find the user by using find() like the following:
const user = await game.users.find(
(gameUser) => gameUser.user == req.user.id
)
The only problem is that the type of gameUser and req.user.id is not the same and I can't use '==='. Is there some way to go through the array and use the mongoose function findById?
As docs explains, findById method:
Finds a single document by its _id field
So you have to use findOne() instead of findById().
Also, to return only one field from the entire array you can use projection into find.
Check this example. This query find an object by its id (i.e. user field) and return only the object, not the whole array.
db.collection.find({
"users": { "$elemMatch": { "user": 1 } }
},
{
"users.$": 1
})
Using mongoose you can do:
yourModel.findOne(({
"users": { "$elemMatch": { "user": 1 } }
},
{
"users.$": 1
})).then(result => {
console.log(result)
}).catch(e => {
// error
})

Mongoose: updating array in document not working

I'm trying to update an array in document by adding object if it doesn't exist, and replacing the object in array otherwise. But nothing ($push, $addToSet) except the $set parameter does anything, and $set works as expected - overwrites the whole array.
My mongoose schema:
var cartSchema = mongoose.Schema({
mail: String,
items: Array
});
The post request handler:
app.post('/addToCart', function(req, res) {
var request = req.body;
Cart.findOneAndUpdate({
"mail": request.mail
}, {
$addToSet: {
"items": request.item
}
}, {
upsert: true
},
function(err, result) {
console.log(result);
}
);
res.send(true);
});
The data that I'm sending from the client:
{
"mail":"test#gmail.com",
"item":{
"_id":"59da78db7e9e0433280578ec",
"manufacturer":"Schecter",
"referenceNo":"Daemon-412",
"type":"Gitare",
"image":"images/ba9727909d6c3c26412341907e7e12041507489988265.jpeg",
"__v":0,
"subcategories":[
"Elektricne"
]
}
}
EDIT:
I also get this log when I trigger 'addToCart' request:
{ MongoError: The field 'items' must be an array but is of type object in
document {_id: ObjectId('5a19ae2884d236048c8c91e2')}
The comparison in $addToSet would succeeded only if the existing document has the exact same fields and values, and the fields are in the same order. Otherwise the operator will fail.
So in your case, request.item always need to be exactly the same.
I would recommend creating a model of "item". Then, your cart schema would be like:
var cartSchema = mongoose.Schema({
mail: String,
items: [{
type: ObjectId,
ref: 'item',
}],
});
And let MongoDB determine if the item exist.
this should work you just need to implement objectExits function that test if the item is that one you're looking for :
Cart.findOne({ "mail": request.mail })
.exec()
.then(cart => {
var replaced = cart.items.some((item, i) => {
if (item._id == request.item._id)) {
cart.items[i] = request.item;
return true;
}
})
if (!replaced) {
cart.items.push(request.item);
}
cart.save();
return cart;
})
.catch(err => {
console.log(err)
});

How to add object to collection inside another collection in MongoDB using Node.js

I know how to add object to collection in MongoDB using Node.js, for example:
router.post('/addProduct', function (req, res) {
Partner.findByIdAndUpdate({ _id: req.body.partnerId }, { $push: { "products": { name: req.body.dataProduct.name } } }, { safe: true }, function (err, response) {
if (err) throw err;
res.json(response);
});
});
but what if in product will be another table? How can I simply add object there?
Let's say this is my schema:
var partnerSchema = new mongoose.Schema({
name: String,
products: [
{
name: String,
campaignList: [
{
name: String,
type: String,
startDate: Date,
endDate: Date,
paymentMethod: String,
partnerPayout: Number,
ourPayout: Number
}
]
}]
});
ID in each partner and product are default ._id eg. partner._id and product._id. That's why aren't in schema above. However I sending them from FrontEnd to BackEnd as a req.parameter - normally thing but i wanted to say it for sure :)
Your best bet would bet to define the Schema & Model for the campaign on its own, and add it to the Partner by reference using the _id
var partnerSchema = new mongoose.Schema({
name: String,
products: [
{
name: String,
campaignList: [
{ type : mongoose.Schema.Types.ObjectId, ref : 'campaignModel' }
]
}]
});
var campaignSchema = new mongoose.Schema({
name: String,
type: String,
startDate: Date,
endDate: Date,
paymentMethod: String,
partnerPayout: Number,
ourPayout: Number
});
var campaignModel = mongoose.model('campaignModel', campaignSchema);
var partnerModel = mongoose.model('partnerSchema', partnerSchema);
A good practice is to look for times where you're trying nest semi-complex data, or objects with more than two or three keys, and extract them into their own collection. Not only does it make it easier to search for those documents, it makes it easier to use them in conjunction with other objects.
Be sure to call .populate() during your query so that MongoDB knows to nest the documents from the other collections, otherwise, you'll just have an array of ObjectId.
First match the required products array position. You can confirm this by testing a simple find like:
Partner.find({_id: req.body.partnerId), 'products.name': req.body.dataProduct.name }, { 'products.$': 1})
Use the positional $ operator to push the new object into the array in the matched product element:
Partner.update({_id: req.body.partnerId), 'products.name': req.body.dataProduct.name }, { $push: { 'products.$.campaignList': { name: 'new campaign' }}})
Reference https://docs.mongodb.com/manual/reference/operator/update/positional/
try this:
router.post('/addProduct', function (req, res) {
Partner.findOneAndUpdate({ _id: req.body.partnerId }, { $push: { "products": { name: req.body.dataProduct.name, $push: {"campaignList": {name: req.body.name}} } } }, { safe: true }, function (err, response) {
if (err) throw err;
res.json(response);
});
});
i hope it helps you

Categories