UpdateOne MongoDB with push using value from another field - javascript

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.

Related

How can I use findOneAndUpdate() in Mongoose, and keep a value the same?

I'm making a system that will increment value1 if x is true, but if y is true it will increment value2. Using the system I have now, it will also reset the value that is not being updated back to 0, I don't know what to do to stop this. I just need the other value to be the same
Here is my code.
leaderboard.findOneAndUpdate(
{
userID: interaction.user.id
},
{
userID: interaction.user.id,
$inc: { accepts: 1 },
denies: 0
},
{
upsert: true, new: true
}, (err: any, doc: any) => {
if (err) console.log(err)
console.log(`Updated ${interaction.user.username}'s accepts to ${doc.accepts} `)
})
So in this example, I need accepts to be incremented by 1, but declines to stay the same that is already in the MongoDB.
Try changing your update query to this
{ $inc: { accepts: 1 } }
Not sure if upsert makes sense in that case. Because it would create a new document with only the accepts field.
{ upsert: true, new: true }
If upsert is needed then build your update query based on the value to set.
E.g.
If (x) {
updateQuery = {
userID: interaction.user.id,
$inc: { accepts: 1 },
}
} else {
updateQuery = {
userID: interaction.user.id,
$inc: { denies: 1 },
}
}

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 } } },

Mongo - Update nested array of objects by _id

How can I access an array of object with their own _id and update it with Mongo/Mongoose?
Take a look to my update query and check if there's something wrong, because this code doesn't return any error, but it doesn't really update the field
modelUser.findOneAndUpdate(
{ userName: body.author, "portfolio._id": body.id },
{ new: true },
{
$set: { //I thing the problem it's over here
"portfolio.$.profitLoss": profitLoss,
"portfolio.$.percentage": percentage
}
},
(err, user) => {
if (err) {
console.log(err);
}
console.log(`Done`);
}
);
This is my User Schema:
const userSchema = new Schema({
...stuff,
portfolio: [
{
coin: String,
amount: String,
price: String,
bought: Date,
profitLoss: String,
percentage: String
}
],
});
Basically i think mongo just don't know which of these sub documents should update, I don't know if there's something like another findOneAndUpdate for sub object/document by id.
Just changed findOneAndUpdate to updateOne and everything works.

delete object from document array in mongodb collection using mongoose

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

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