0

I've come across the moments with updating the elements in array of documents.

So far there are two ways to implement that:

            const product = await ProductModel.findOne({ _id: productID });
            const price = product.prices.find( (price: any) => price._id == id );

            if(!price) {
                return {
                    type: 'ProductPriceError',
                    code: 404,
                    message: `Coundn't find price with provided ID: ${id}`,
                    success: false,
                }
            }

            product.prices.pull({ _id: id })
            product.prices.push(Object.assign(price, payload))
            await product.save()

The approach above is not atomic and not very comfortable, requires many operations - 2 in/out operations with Mongoose and 2 manipulations with the mongoose document (pulling and pushing back element), and 1 linear search for the item I need to modify.

And another issue with this approach that it completely replaces the item and changes the order of items in the array.

It's too verbose and not an efficient way, but it gives you more control over the operation.

Another way to complete it is:

            const product = await ProductModel.updateOne(
                { _id: productID, 'prices._id': id },
                { $set: { 'prices.$': { ...payload, _id: id } } },
            )

So, apparently, you can use it only with updateOne. It seems to work well but if the search query fails to find the doc or an object in the array it flows silently with no errors. You can only rely on the response with the number of modifications that were made during the execution. nModified: 1 but the operation status is ok: 1 anyway.

When I try to use { upsert: true } what should insert the fields if they don't exist it finally throws an error that the positional operator cannot find the element to insert in. That solves one problem with the silent passing of the operation when there is no element to modify. But anyone it's not the way it should work - because it should inset a new document and create the fields (it would be logical).

How can I with one single (atomic) operation update the document in an array of a mongoose document and return back that updated documents or fields?

0 Answers0