updating multiple different array object elements in mongodb with nodejs - node.js

mongodb collection:
"_id": ObjectId("5e2ac528e9d99f3074f31de7"),
"publications": [
{
"_id": ObjectId("5e2ac528e9d99f3074f31de8"),
"name": "Times of India",
"productCode": "TCE1",
"tradeCopies": 40
},
{
"_id": ObjectId("5e2ac528e9d99f3074f31de9"),
"publicationName": "Economic Times",
"productCode": "ECE1",
"tradeCopies": 100
}
],
"orderCreatedBy": ObjectId("5e2977e1cc1208c65c00648b"),
"submittedTo": ObjectId("5e2555363405363bc4bf86c2"),
Nodejs Code
i would get multiple "productCode" like "TCE1","ECE1" etc,and i need to update tradeCopies of all the object array elements in one go according to their productCodes
Here is what i tried
exports.editOrder = async (req, res, next) => {
const { orderId, dealerId, productCode, tradeCopies } = req.body;
try{
const orders: await Order.updateOne(
{ _id: orderId,
submittedTo: dealerId,
"publications.productCode": productCode},
{$set:{"publications.$.tradeCopies":50}}
)
res.status(200).json({
orders,
message: "order submitted"
});
} catch (error) {
res.send(error);
}
};
CONCERNS
1-this query is updating only 1 array object element according to the matched productCode i want all the tradeCopies of all the array objects according to their productCodes to be updated in onego
2- the above query is working only in mongo Shell not in nodejs driver and whenever i remove double quotes in nodejs query vscode shows there might an error

You want to use arrayFilters.
const orders: await Order.updateOne(
{ _id: orderId,
submittedTo: dealerId,
"publications.productCode": productCode
},
{ $set: { "publications.$[element].tradeCopies":50 } },
{ arrayFilters: [ { "element.productCode": productCode } ] }
)
I'm not sure what you mean by removing the double quotes, but this snippet is nodejs driver compatible.

Related

How can I find specific document and update a value of specific key inside array?

I have a structure like this:
{
_id: new ObjectId("634aa49f98e3a05346dd2327"),
filmName: 'Film number 1',
episodes: [
{
episodeName: 'Testing 1',
slugEpisode: 'testing-1',
_id: new ObjectId("6351395c17f08335f1dabfc9")
},
{
episodeName: 'Testing 2',
slugEpisode: 'testing-2',
_id: new ObjectId("6351399d9a2533b9be1cbab0")
},
],
},
{
_id: new ObjectId("634aa4cc98e3a05346dd232a"),
filmName: 'Film number 2',
episodes: [
{
episodeName: 'Something 1',
slugEpisode: 'something-1',
_id: new ObjectId("6367cce66d6b85442f850b3a")
},
{
episodeName: 'Something 2',
slugEpisode: 'something-2',
_id: new ObjectId("6367cd0e6d6b85442f850b3e")
},
],
}
I received 3 fields:
_id: Film _id
episodeId: Episode _id
episodeName: The content I wish to update
I tried to find a specific Film ID to get a specific film, and from then on, I pass an Episode ID to find the exact episode in the episodes array. Then, update the episodeName of that specific episode.
Here's my code in NodeJS:
editEpisode: async (req, res) => {
const { _id } = req.params
const { episodeId, episodeName } = req.body
try {
const specificResult = await Films.findOneAndUpdate(
{ _id, 'episodes._id': episodeId },
{ episodeName }
)
console.log(specificResult)
res.json({ msg: "Success update episode name" })
} catch (err) {
return res.status(500).json({ msg: err.message })
}
},
But what console.log display to me is a whole document, and when I check in MongoDB, there was no update at all, does my way of using findOneAndUpdate incorrect?
I'm reading this document: MongooseJS - Find One and Update, they said this one gives me the option to filter and update.
The MongoDB server needs to know which array element to update. If there is just one array element to update, here's one way you could do it. (I picked a specific element. You would use your req.params and req.body.)
db.films.update({
"_id": ObjectId("634aa4cc98e3a05346dd232a"),
"episodes._id": ObjectId("6367cd0e6d6b85442f850b3e")
},
{
"$set": {
"episodes.$.episodeName": "Something Two"
}
})
Try it on mongoplayground.net.
You can use the filtered positional operator $[<identifier>] which essentially finds the element or object (in your case) with a filter condition and updates that.
Query:
const { _id } = req.params
const { episodeId, episodeName } = req.body
await Films.update({
"_id": _id
},
{
$set: {
"episodes.$[elem].episodeName": episodeName
}
},
{
arrayFilters: [
{
"elem._id": episodeId
}
]
})
Check it out here for example purpose I've put ids as numbers and episode name to update as "UpdatedValue"

Update nested object in array MongoDB

I need to find and update documents with category that corresponding to the query. Array could contain mo than one corresponding id.
Query:
{
"ids": ["61f1cda47018c60012b3dd01", "61f1cdb87018c60012b3dd07"],
"userId": "61eab3e57018c60012b3db3f"
}
I got collection with documents like:
`{
"_id":{"$oid":"61f1cdd07018c60012b3dd09"},
"expenses":[
{"category":"61eafc104b88e154caa58616","price":"1111.00"},
{"category":"61f1cdb87018c60012b3dd07","price":"2222.00"},
{"category":"61f1cda47018c60012b3dd01","price":"1241.00"},
{"category":"61f1cdb87018c60012b3dd07","price":"111.00"}
],
"userId":"61eab3e57018c60012b3db3f"
}`
my method:
async myMethod(ids: [string], userId: string) {
try {
const { ok } = await this.ExpensesModel.updateMany(
{"userId": userId, "expenses.category": { $in: ids }},
{$set: {"expenses.$.category": "newCategoryID"}}
);
return ok
} ........
I path array of ids ["61f1cda47018c60012b3dd01","61f1cdb87018c60012b3dd07","61f1cdb87018c60012b3dd07"] and userId, this code update only 1 category by document.
So can i made it with mongo build in methods? or i need to find matching document and update it it by my self and after that update or insert;
Update with arrayFilters
db.collection.update({
"expenses.category": {
$in: [
"61f1cda47018c60012b3dd01",
"61f1cdb87018c60012b3dd07"
]
}
},
{
$set: {
"expenses.$[elem].category": "61eab3e57018c60012b3db3f"
}
},
{
arrayFilters: [
{
"elem.category": {
$in: [
"61f1cda47018c60012b3dd01",
"61f1cdb87018c60012b3dd07"
]
}
}
]
})
mongoplayground

Cannot find id and update and increment sub-document - returns null Mongoose/mongoDB

I have a problem where I cannot seem to retrieve the _id of my nested objects in my array. Specifically the foods part of my object array. I want to find the _id, of lets say risotto, and then increment the orders count dynamically (from that same object).
I'm trying to get this done dynamically as I have tried the Risotto id in the req.body._id and thats fine but i can't go forward and try to increment orders as i get null.
I keep getting null for some reason and I think its a nested document but im not sure. heres my route file and schema too.
router.patch("/update", [auth], async (req, res) => {
const orderPlus = await MenuSchema.findByIdAndUpdate({ _id: '5e3b75f2a3d43821a0fb57f0' }, { $inc: { "food.0.orders": 1 }}, {new: true} );
//want to increment orders dynamically once id is found
//not sure how as its in its own seperate index in an array object
try {
res.status(200).send(orderPlus);
} catch (err) {
res.status(500).send(err);
}
});
Schema:
const FoodSchema = new Schema({
foodname: String,
orders: Number,
});
const MenuSchema = new Schema({
menuname: String,
menu_register: Number,
foods: [FoodSchema]
});
Heres the returned Database JSON
{
"_id": "5e3b75f2a3d43821a0fb57ee",
"menuname": "main course",
"menu_register": 49,
"foods": [
{
"_id": "5e3b75f2a3d43821a0fb57f0",
"foodname": "Risotto",
"orders": 37
},
{
"_id": "5e3b75f2a3d43821a0fb57ef",
"foodname": "Tiramisu",
"orders": 11
}
],
"__v": 0
}
the id for the menuname works in its place but i dont need that as i need to access the foods subdocs. thanks in advance.
You are sending food id (5e3b75f2a3d43821a0fb57f0) to the MenuSchema.findByIdAndUpdate update query. It should be the menu id which is 5e3b75f2a3d43821a0fb57ee
You can find a menu by it's id, and update it's one of the foods by using food _id or foodname using mongodb $ positional operator.
Update by giving menu id and food id:
router.patch("/update", [auth], async (req, res) => {
try {
const orderPlus = await MenuSchema.findByIdAndUpdate(
"5e3b75f2a3d43821a0fb57ee",
{ $inc: { "foods.$[inner].orders": 1 } },
{ arrayFilters: [{ "inner._id": "5e3b75f2a3d43821a0fb57f0" }], new: true }
);
res.status(200).send(orderPlus);
} catch (err) {
res.status(500).send(err);
}
});
Update by giving menu id and foodname:
router.patch("/update", [auth], async (req, res) => {
try {
const orderPlus = await MenuSchema.findByIdAndUpdate(
"5e3b75f2a3d43821a0fb57ee",
{ $inc: { "foods.$[inner].orders": 1 } },
{ arrayFilters: [{ "inner.foodname": "Risotto" }], new: true }
);
res.status(200).send(orderPlus);
} catch (err) {
res.status(500).send(err);
}
});

need to update field with condition in mongodb

I am doing currently doing as
if (part.qty) {
part.status = 'In Stock';
}
const part = new partsModel(part);
return part.save();
is it possible do this in MongoDB query only without using if statement both insert and update
You can try something like:
const filterObj = {
"$or": [{
"qty": {
"$exists": true
}
}, {
"qty": {
"$ne": null
}
}, {
"qty": {
"$ne": 0 //based on what type of value you have in qty
}
}]
};
const updateObj = {
"$set": {
"status": "In Stock"
}
};
partsModel.update(filterObj, updateObj)
.then(result => {
console.log(result);
})
.catch(err => {
console.log(err);
});
This will update the first matching record with our filters. If you wanna update all matching records use updateMany() instead.
Check out the official mongoose docs for more details.
P.s: You may need some modifications as i couldn't get a chance to try the code. hope this helps :)

create a new object Id in mongoDB using node js

I am using the below code to insert data to mongodb
router.post('/NewStory', function (req, res) {
var currentObject = { user: userId , story : story , _id:new ObjectID().toHexString() };
req.db.get('clnTemple').findAndModify({
query: { _id: req.body.postId },
update: { $addToSet: { Stories: currentObject } },
upsert: true
});
});
This code is working fine if i remove the _id:new ObjectID().toHexString()
What i want to achieve here is that for every new story i want a unique _id object to be attached to it
What am i doing wrong?
{
"_id": {
"$oid": "55ae24016fb73f6ac7c2d640"
},
"Name": "some name",
...... some other details
"Stories": [
{
"userId": "105304831528398207103",
"story": "some story"
},
{
"userId": "105304831528398207103",
"story": "some story"
}
]
}
This is the document model, the _id that i am trying to create is for the stories
You should not be calling .toHexString() on this as you would be getting a "string" and not an ObjectID. A string takes more space than the bytes of an ObjectId.
var async = require('async'),
mongo = require('mongodb'),
db = require('monk')('localhost/test'),
ObjectID = mongo.ObjectID;
var coll = db.get('junk');
var obj = { "_id": new ObjectID(), "name": "Bill" };
coll.findAndModify(
{ "_id": new ObjectID() },
{ "$addToSet": { "stories": obj } },
{
"upsert": true,
"new": true
},
function(err,doc) {
if (err) throw err;
console.log(doc);
}
)
So that works perfectly for me. Noting the "new" option there as well so the modified document is returned, rather than the original form of the document which is the default.
{ _id: 55c04b5b52d0ec940694f819,
stories: [ { _id: 55c04b5b52d0ec940694f818, name: 'Bill' } ] }
There is however a catch here, and that is that if you are using $addToSet and generating a new ObjectId for every item, then that new ObjectId makes everything "unique". So you would keep adding things into the "set". This may as well be $push if that is what you want to do.
So if userId and story in combination already make this "unique", then do this way instead:
coll.findAndModify(
{
"_id": docId,
"stories": {
"$not": { "$elemMatch": { "userId": userId, "story": story } }
}
},
{ "$push": {
"stories": {
"userId": userId, "story": story, "_id": new ObjectID()
}
}},
{
"new": true
},
function(err,doc) {
if (err) throw err;
console.log(doc);
}
)
So test for the presence of the unique elements in the array, and where they do not exist then append them to the array. Also noting there that you cannot do an "inequality match" on the array element while mixing with "upserts". Your test to "upsert" the document should be on the primary "_id" value only. Managing array entries and document "upserts" need to be in separate update operations. Do not try an mix the two, otherwise you will end up creating new documents when you did not intend to.
By the way, you can generate an ObjectID just using monk.
var db = monk(credentials.database);
var ObjectID = db.helper.id.ObjectID
console.log(ObjectID()) // generates an ObjectID

Resources