MongoDB BulkWrite update operation $set not working

I am looping through products (variable records) with a bulkWrite updateOne operation on each product.

Once I update the records I can see the reservations array is being added to the document, totalQuantity is updated to the expected value (e.g: if the totalQuantity is 2000 and the loadingTotal is 600 then the updated totalQuantity is 1400)

for (const el of records) {
        promiseArray.push(
          Stock.bulkWrite(
            [
              {
                updateOne: {
                  filter: {
                    index: el.index,
                    product: el.product,
                    batchNo: el.batchNo,
                    agency,
                    totalQuantity: { $gte: el.loadingTotal },
                  },
                  update: {
                    $push: {
                      reservations: {
                        loadingSheetId: sheetAfterSave._id,
                        reservedCaseQuantity: el.loadingCaseCount,
                        reservedUnitQuantity: el.loadingUnitCount,
                        reservedTotalQuantity: el.loadingTotal,
                      },
                    },
                    $inc: { totalQuantity: -el.loadingTotal },
                    $set: { currentQuantity: "$totalQuantity" } // Issue
                  },
                },
              },
            ],
            { session: session }
          )
        );
      }

  const result = await Promise.all(promiseArray);
  console.log('******** Result Promise ********', result);

As you can see in line $set: { currentQuantity: “$totalQuantity” } I am trying to assign latest totalQuantity value (1400) to currentQuantity after $inc operation. But this is not working. Getting below error

[distribution] CastError: Cast to Number failed for value "$totalQuantity" at path "currentQuantity"
[distribution]     at SchemaNumber.cast (/app/node_modules/mongoose/lib/schema/number.js:384:11)
[distribution]     at SchemaNumber.SchemaType.applySetters (/app/node_modules/mongoose/lib/schematype.js:1031:12)
[distribution]     at SchemaNumber.SchemaType._castForQuery (/app/node_modules/mongoose/lib/schematype.js:1459:15)
[distribution]     at SchemaNumber.castForQuery (/app/node_modules/mongoose/lib/schema/number.js:436:14)
[distribution]     at SchemaNumber.SchemaType.castForQueryWrapper (/app/node_modules/mongoose/lib/schematype.js:1428:15)
[distribution]     at castUpdateVal (/app/node_modules/mongoose/lib/helpers/query/castUpdate.js:520:19)
[distribution]     at walkUpdatePath (/app/node_modules/mongoose/lib/helpers/query/castUpdate.js:347:22)
[distribution]     at castUpdate (/app/node_modules/mongoose/lib/helpers/query/castUpdate.js:94:7)
[distribution]     at /app/node_modules/mongoose/lib/helpers/model/castBulkWrite.js:70:37
[distribution]     at /app/node_modules/mongoose/lib/model.js:3502:35
[distribution]     at each (/app/node_modules/mongoose/lib/helpers/each.js:11:5)
[distribution]     at /app/node_modules/mongoose/lib/model.js:3502:5
[distribution]     at /app/node_modules/mongoose/lib/helpers/promiseOrCallback.js:31:5
[distribution]     at new Promise (<anonymous>)
[distribution]     at promiseOrCallback (/app/node_modules/mongoose/lib/helpers/promiseOrCallback.js:30:10)
[distribution]     at Function.Model.bulkWrite (/app/node_modules/mongoose/lib/model.js:3500:10) {
[distribution]   stringValue: '"$totalQuantity"',
[distribution]   messageFormat: undefined,
[distribution]   kind: 'Number',
[distribution]   value: '$totalQuantity',
[distribution]   path: 'currentQuantity',
[distribution]   reason: AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:
[distribution]
[distribution]     assert.ok(!isNaN(val))
[distribution]
[distribution]       at castNumber (/app/node_modules/mongoose/lib/cast/number.js:28:10)
[distribution]       at SchemaNumber.cast (/app/node_modules/mongoose/lib/schema/number.js:382:12)
[distribution]       at SchemaNumber.SchemaType.applySetters (/app/node_modules/mongoose/lib/schematype.js:1031:12)
[distribution]       at SchemaNumber.SchemaType._castForQuery (/app/node_modules/mongoose/lib/schematype.js:1459:15)
[distribution]       at SchemaNumber.castForQuery (/app/node_modules/mongoose/lib/schema/number.js:436:14)
[distribution]       at SchemaNumber.SchemaType.castForQueryWrapper (/app/node_modules/mongoose/lib/schematype.js:1428:15)
[distribution]       at castUpdateVal (/app/node_modules/mongoose/lib/helpers/query/castUpdate.js:520:19)
[distribution]       at walkUpdatePath (/app/node_modules/mongoose/lib/helpers/query/castUpdate.js:347:22)
[distribution]       at castUpdate (/app/node_modules/mongoose/lib/helpers/query/castUpdate.js:94:7)
[distribution]       at /app/node_modules/mongoose/lib/helpers/model/castBulkWrite.js:70:37
[distribution]       at /app/node_modules/mongoose/lib/model.js:3502:35
[distribution]       at each (/app/node_modules/mongoose/lib/helpers/each.js:11:5)
[distribution]       at /app/node_modules/mongoose/lib/model.js:3502:5
[distribution]       at /app/node_modules/mongoose/lib/helpers/promiseOrCallback.js:31:5
[distribution]       at new Promise (<anonymous>)
[distribution]       at promiseOrCallback (/app/node_modules/mongoose/lib/helpers/promiseOrCallback.js:30:10) {
[distribution]     generatedMessage: true,
[distribution]     code: 'ERR_ASSERTION',
[distribution]     actual: false,
[distribution]     expected: true,
[distribution]     operator: '=='
[distribution]   }
[distribution] }

Can someone help me with this issue?? Thanks

Hello @Shanka_Somasiri, welcome to the MongoDB community forum.

You cannot assign a document field’s (totalQuantity) value in an update operation like that - hence the error. But, you can use the Updates with Aggregation Pipeline to do such an update using the document field’s value.

Note that this feature is supported only with MongoDB v4.2 or newer.

Thanks @Prasad_Saya for the insight. I will try Updates with Aggregation Pipeline — MongoDB Manual and will update you.

Appreciate your help

@Prasad_Saya Unfortunately I cannot use pipeline operators such as $inc this way. Getting error

[distribution] MongoError: Unrecognized expression '$inc'
[distribution]     at Function.create (/app/node_modules/mongoose/node_modules/mongodb/lib/core/error.js:51:12)
[distribution]     at toError (/app/node_modules/mongoose/node_modules/mongodb/lib/utils.js:149:22)
[distribution]     at /app/node_modules/mongoose/node_modules/mongodb/lib/operations/common_functions.js:376:39
[distribution]     at handler (/app/node_modules/mongoose/node_modules/mongodb/lib/core/sdam/topology.js:913:24)
[distribution]     at /app/node_modules/mongoose/node_modules/mongodb/lib/cmap/connection_pool.js:356:13
[distribution]     at handleOperationResult (/app/node_modules/mongoose/node_modules/mongodb/lib/core/sdam/server.js:493:5)
[distribution]     at commandResponseHandler (/app/node_modules/mongoose/node_modules/mongodb/lib/core/wireprotocol/command.js:123:25)
[distribution]     at MessageStream.messageHandler (/app/node_modules/mongoose/node_modules/mongodb/lib/cmap/connection.js:272:5)
[distribution]     at MessageStream.emit (node:events:376:20)
[distribution]     at processIncomingData (/app/node_modules/mongoose/node_modules/mongodb/lib/cmap/message_stream.js:144:12)
[distribution]     at MessageStream._write (/app/node_modules/mongoose/node_modules/mongodb/lib/cmap/message_stream.js:42:5)
[distribution]     at writeOrBuffer (node:internal/streams/writable:395:12)
[distribution]     at MessageStream.Writable.write (node:internal/streams/writable:340:10)
[distribution]     at TLSSocket.ondata (node:internal/streams/readable:748:22)
[distribution]     at TLSSocket.emit (node:events:376:20)
[distribution]     at addChunk (node:internal/streams/readable:311:12) {
[distribution]   driver: true,
[distribution]   index: 0,
[distribution]   code: 168
[distribution] }

@Prasad_Saya There was an implementation issue on my behalf. Its working now as expected.

Thanks alot for your help. Cheers

How can i get the latest totalQuantity in below code after $inc: { totalQuantity: -el.loadingTotal } operation? I am stuck at this point. Any ideas??

promiseArray.push(
          Stock.updateOne(
            {
              index: el.index,
              product: el.product,
              batchNo: el.batchNo,
              agency,
              totalQuantity: { $gte: el.loadingTotal },
            },
            {
              $push: {
                reservations: {
                  loadingSheetId: sheetAfterSave._id,
                  reservedCaseQuantity: el.loadingCaseCount,
                  reservedUnitQuantity: el.loadingUnitCount,
                  reservedTotalQuantity: el.loadingTotal,
                },
              },
              $inc: { totalQuantity: -el.loadingTotal },
              $set: { currentQuantity:  },  // How can i get the updated totalQuantity here
            },
            {
              session: session,
            }
          )
        );

As I had mentioned earlier you cannot do that without using an Update With Aggregation Pipeline. The operators you can use within the pipeline are Aggregation Pipeline Operators - not the Update Operators ($inc, $push and $set).

You can use the Aggregation Pipeline Operators - $add instead of $inc, $concatArrays instead of $push and then assign the totalQuantity to the currentQuantity.

You need to get familiar with using the Aggregation queries to understand and work with Updates With Aggregation Pipeline. Here are some example posts:

Hi @Prasad_Saya

This is my latest code. I am new to aggregate pipeline operations and might need some help.

promiseArray.push(
          Stock.updateOne(
            {
              index: el.index,
              product: el.product,
              batchNo: el.batchNo,
              agency,
              totalQuantity: { $gte: el.loadingTotal },
            },
            {
              $set: {
                reservations: {
                  $concatArrays: [
                    { $slice: ['$reservations', 1] },
                    [
                      {
                        loadingSheetId: sheetAfterSave._id,
                        reservedCaseQuantity: el.loadingCaseCount,
                        reservedUnitQuantity: el.loadingUnitCount,
                        reservedTotalQuantity: el.loadingTotal,
                      },
                    ],
                  ],
                },
              },
            },
            {
              session: session,
            }
          )
        );

But this does not properly push the objects to reservation array even though a reservation is being added.

image

As you can see in the above screen shot loadingSheetId: sheetAfterSave._id, is missing. Also the quantities are always zero. Any ideas why??

Hi @Shanka_Somasiri, I am not sure about what you are trying. Here is how you do the update using Aggregation Pipeline, for example.

I have an input document:

{
   _id: 1,
   reservations: [ ]
}

Here is a document I want to push into the reservations array.

var docToUpdate = { loadingShetId: 12, reservedCaseQty: 200 }

The update query:

db.test.updateOne(
  { _id: 1 },
  [
    {
         $set: {
             reservations: {
                 $concatArrays: [ "$reservations", [ docToUpdate ] ]
             }
         }
    }
  ]
)

The updated document:

{
        "_id" : 1,
        "reservations" : [
                {
                        "loadingShetId" : 12,
                        "reservedCaseQty" : 200
                }
        ]
}


The remaining field updates:

$inc: { totalQuantity: -el.loadingTotal }
$set: { currentQuantity: "$totalQuantity" }

Can be coded as follows:

totalQuantity: { $add: [ "$totalQuantity", -el.loadingTotal ] }
currentQuantity: "$totalQuantity"

So, the update query will become:

db.test.updateOne(
  { _id: 1 },
  [
    {
         $set: {
             reservations: {
                 $concatArrays: [ "$reservations", [ docToUpdate ] ]
             },
             totalQuantity: { $add: [ "$totalQuantity", -el.loadingTotal ] },
             currentQuantity: "$totalQuantity"
         }
    }
  ]
)
1 Like

@Prasad_Saya This worked perfectly. I had some issue with my code.
Thank you sooo much again. I was stuck with this for days now and appreciate your help. :pray: :pray: :pray:

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.