Reputation: 247
I have a document like this one:
{
_id:ObjectId('111'),
products:[
{
_id:ObjectId('aaa'),
quantity:2,
price:800
}
]
}
I want to update price field by multiplying it with quantity field ie (2 * 800) of which the result gets updated/assigned to price. (as for this example price gets updated to 1600).
Document after Update :
{
_id:ObjectId('111'),
products:[
{
_id:ObjectId('aaa'),
quantity:2,
price:1600 //the updated field by multiplying the initial 800 * 2
}
]
}
My query for selecting is like this below:
Shop.findOneAndUpdate(
{ "_id": '111, "products._id": 'aaa' }
)
How can I achieve this?
Upvotes: 0
Views: 954
Reputation: 17858
As @Casey suggested in the comments, you can do this in multi step, find the shop, find the product, change product price, save the shop.
router.patch("/shops/:shopId/:productId", async (req, res) => {
const { shopId, productId } = req.params;
let shop = await Shop.findById(shopId);
if (!shop) return res.status(400).send("Shop not found");
const productIndex = shop.products.findIndex((p) => p._id.toString() === productId);
if (productIndex < 0) return res.status(400).send("Product not found in shop");
let product = shop.products[productIndex];
product.price *= product.quantity;
shop = await shop.save();
res.send(shop);
});
Let's say you have this existing shop with two products:
{
"_id": "5eb85ab17c2bfb3e2cfc15d0",
"products": [
{
"_id": "5eb85ab17c2bfb3e2cfc15d2",
"quantity": 2,
"price": 800
},
{
"_id": "5eb85ab17c2bfb3e2cfc15d1",
"quantity": 3,
"price": 500
}
]
}
If you want to update the price with the "_id": "5eb85ab17c2bfb3e2cfc15d2"
, we send a patch request to the url http://your base url/shops/5eb85ab17c2bfb3e2cfc15d0/5eb85ab17c2bfb3e2cfc15d2
The output will be like this:
{
"_id": "5eb85ab17c2bfb3e2cfc15d0",
"products": [
{
"_id": "5eb85ab17c2bfb3e2cfc15d2",
"quantity": 2,
"price": 1600 => UPDATED
},
{
"_id": "5eb85ab17c2bfb3e2cfc15d1",
"quantity": 3,
"price": 500
}
]
}
Upvotes: 3
Reputation: 17915
On MongoDB version >= 4.2
as you can execute aggregation-pipeline in updates, try below query :
Shop.update(
/** Remember to convert input strings to type `ObjectId()` prior to querying */
{ _id: ObjectId("111"), "products._id": ObjectId("aaa") },
/** This aggregation pipeline will re-create `products` array,
* if condition is met for an object then price will be multiplied & price field is merged to original object & pushed back to `products` array,
* if condition is not met actual object is pushed back to array */
[
{
$set: {
products: {
$map: {
input: "$products",
in: {
$cond: [
{ $eq: ["$$this._id", ObjectId("aaa")] },
{
$mergeObjects: [ "$$this", { price: { $multiply: ["$$this.quantity", "$$this.price"] }}]
},
"$$this"
]
}
}
}
}
}
]
);
Upvotes: 1