I saw that MongoDB 4.2 introduces aggregation pipeline updates, which allows you to set document fields based on other fields in the document.
Considering the following document
{
ean: "12345",
orderedQty: 2,
fulfilledQty: 1,
"status": "pending"
}
I could use the following command to increment the fulfilledQty by 1 and if the orderedQty matches the fulfilledQty set the status accordingly:
db.collection.findOneAndUpdate({}, [
{
"$set": {
"orderedQty": {
"$add": [ "$fulfilledQty", 1 ]
}
},
"$set": {
"status": {
"$cond": {
"if": { "$eq": ["$orderedQty", "$fulfilledQty"] },
"then": "fulfilled",
"else": "pending"
}
}
}
}
])
My question: How would i perform this on an array. Say I have a document like this:
_id: "test",
items: [
{ean: "12345", orderedQty: 2, fulfilledQty: 1, "status": "pending"},
{ean: "67891", orderedQty: 1, fulfilledQty: 1, "status": "fulfilled"}
]
Given I have the params ean = 12345
and an increase value by 1. How could I target the specific array item with EAN 12345, increase the fulfilledQty by 1 and set the status? I want to only chance the status field and fulfilledQty field and leave the rest of the items array as is. So expected outcome would be:
_id: "test",
items: [
{ean: "12345", orderedQty: 2, fulfilledQty: 2, "status": "fulfilled"},
{ean: "67891", orderedQty: 1, fulfilledQty: 1, "status": "fulfilled"}
]
I found the following workflow (works only for mongodb 4.2+), but it's amazingly verbose…
Given that there are two variables, an item identifier (called ean
) and a quantity that was shipped (called fulfilledQty
)
collection.update({}, [
{
$set: {
items: {
$map: {
input: "$items",
as: "item",
in: {
$mergeObjects: [
"$$item",
{
fulfilledQty: {
$switch: {
branches: [
{
case: {
$eq: ["$$item.ean", ean]
},
then: {
$toInt: {
$add: ["$$item.fulfilledQty", fulfilledQty]
}
}
}
],
default: "$$item.fulfilledQty"
}
}
}
]
}
}
}
}
},
{
$set: {
items: {
$map: {
input: "$items",
as: "item",
in: {
$mergeObjects: [
"$$item",
{
status: {
$cond: {
if: {
$eq: ["$$item.orderedQty", "$$item.fulfilledQty"]
},
then: "fulfilled",
else: "$$item.status"
}
}
}
]
}
}
}
}
}
]);
I used a switch statement since in my use case I have multiple different EANs. Downside is that I had to use a $map operation, so it always iterates over the whole items array.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With