How to update nested array using arrayFilters, but if it doesn't find a match it should insert new values

I have this document and what I’m trying to do is to push new values into offers array, but to specific quantities._id. If it matches userId from arrayFilters it should just update that value in offers array.

{
	"_id" : ObjectId("61043db60d237d00049712ad"),
	"__v" : 0,
	"quantities" : [
		{
			"_id" : ObjectId("61043db60d237d00049712ae"),
			"quantity" : 500,
			"aimedPrice" : 3.25,
			"offers" : [ ]
		}
	],
	"technology" : [ ]
}

So here’s what I wrote, it does update, but it won’t create a new value in this offers array.

db.positions.updateOne({
    "_id": ObjectId("61043db60d237d00049712ad"),
    "quantities._id": ObjectId("61043db60d237d00049712ae")
}, {
    $addToSet: {
        "quantities.$[qty].offers": {
            userId: ObjectId('60d794ba17471000041a7ef2'),
            seen: false,
            offeredQuantityPrice: 45.5,
            realisticDeliveryTime: ISODate("2023-10-16T02:00:00.000+02:00"),
            dateOffered: ISODate("2023-09-14T22:13:41.970+02:00"),
        }
    }
}, {
    arrayFilters: [
        { "qty.offers.userId": ObjectId('60d794ba17471000041a7ef2') }
    ],
    upsert: true
})

I have been thinking about this and was not able to come up with a better solution than the following:

Use and ordered bulkWrite with 2 updateOne documents. The firstOne to handle the case where the new value has to be updated and the second updateOne to handle the case where the value needs to be added.

1 Like

I actually did a similar thing, removed all values from the array and then insert a new one, since they have to be unique by userId

const bulkOperations = [];

bulkOperations.push({
  updateOne: {
    filter: {
      _id: ObjectId(positionId),
      'quantities._id': ObjectId(quantityId),
    },
    update: {
      $pull: {
        'quantities.$.offers': { userId: ObjectId(otherArgs.userId) },
      },
    },
  },
});

bulkOperations.push({
  updateOne: {
    filter: {
      _id: ObjectId(positionId),
      'quantities._id': ObjectId(quantityId),
    },
    update: {
      $push: {
        'quantities.$.offers': { ...otherArgs },
      },
    },
  },
});

await Position.bulkWrite(bulkOperations, { ordered: true });
1 Like