Loop on array, then update an object field using ObjectId

Hello people, in the following example I have a company named Colors Company that owns many shops

{
    _id: ObjectId("78391283"),
    name: "Colors company",
    shops: [
        {shopID: ObjectId("123456a1cb"), income: 0},
        {shopID: ObjectId("2a1cb67890"), income: 0},
        {shopID: ObjectId("2a1cb010111"), income: 0},
        ...
      ],
}

I need to :
1- Loop on the shops array, find the requested array using {parsedBody.shopID}
2- Get use of the amount stored in “shop.$.income”
2- Increase the income using {parsedBody.amountToAdd}

This is the POST request parsedBody :

{
    companyID: "78391283",
    shopID: "123456a1cb",
    amountToAdd: 200,
}

What i’ve tried

const ObjectId = require("mongoose").Types.ObjectId;

Shops.findOneAndUpdate(
    { _id: parsedBody.shopID},
    {
        set: {
        // <-- missing loop here
        "shops.$.income": { parsedBody.amountToAdd + income }
        }
    }
)

I’m using Next js 13.

Thanks for your help !

Hi @Slog_Go - Welcome to the community.

I’m not too sure if this suits your use case exactly, but i’ve created the following test document in my test environment:

DB>db.test.find()
[
  {
    _id: ObjectId("639122b0136ffe0bdd036073"),
    name: 'Colors company',
    shops: [
      { shopID: ObjectId("639122b0136ffe0bdd036072"), income: 0 },
      { shopID: ObjectId("639122b2136ffe0bdd036074"), income: 0 },
      { shopID: ObjectId("639122b3136ffe0bdd036075"), income: 0 },
      { shopID: ObjectId("639122b4136ffe0bdd036076"), income: 0 },
      { shopID: ObjectId("639122b5136ffe0bdd036077"), income: 0 },
      { shopID: ObjectId("639122b5136ffe0bdd036078"), income: 0 }, /// Last 3 elements with same shopID value
      { shopID: ObjectId("639122b5136ffe0bdd036078"), income: 0 }, /// Last 3 elements with same shopID value
      { shopID: ObjectId("639122b5136ffe0bdd036078"), income: 0 } ///Last 3 elements with same shopID value
    ]
  }
]

Note: the last 3 objects within the shops array have the same "shopID" value.

I’ve done this to try demonstrate the behaviour of the $[<identifier>] positional operator.

Running the following update command:

DB> db.test.updateOne(
  {_id: ObjectId("639122b0136ffe0bdd036073"), 'shops.shopID': ObjectId("639122b5136ffe0bdd036078")},
  {$inc: {'shops.$[element].income': 200}},
  {arrayFilters:[{'element.shopID':ObjectId("639122b5136ffe0bdd036078")}]}
)
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}

The test document after the above update:

DB>db.test.find()
[
  {
    _id: ObjectId("639122b0136ffe0bdd036073"),
    name: 'Colors company',
    shops: [
      { shopID: ObjectId("639122b0136ffe0bdd036072"), income: 0 },
      { shopID: ObjectId("639122b2136ffe0bdd036074"), income: 0 },
      { shopID: ObjectId("639122b3136ffe0bdd036075"), income: 0 },
      { shopID: ObjectId("639122b4136ffe0bdd036076"), income: 0 },
      { shopID: ObjectId("639122b5136ffe0bdd036077"), income: 0 },
      { shopID: ObjectId("639122b5136ffe0bdd036078"), income: 200 },
      { shopID: ObjectId("639122b5136ffe0bdd036078"), income: 200 },
      { shopID: ObjectId("639122b5136ffe0bdd036078"), income: 200 }
    ]
  }
]

"income" incremented by 200 for each of the elements where shopID: ObjectId("639122b5136ffe0bdd036078")

The above was done in mongosh but you can alter it accordingly to test for your driver.

Please note that this was only briefly tested on a single test document so I would advise you test thoroughly in your own test environment to verify it suits all your use case(s) and requirement(s) before moving to production in the case you believe this is what you are after.

If you still require further assistance, please advise what the expected output is to be.

Hope this helps.

Regards,
Jason

1 Like