TKX
TKX

Reputation: 71

Push a document if not exist, update if exist in a nested array with mongoose

I have mongo document and when a new order appear, I need to push it or update (increment the quantity) if an order of a part_id already exist.

   {
       user_id: '13',     
       stock: [
         {
           part_id: 'P456',
           quantity: 3
         },
         {
           part_id: 'P905',
           quantity: 8
         }
       ]
    }

I have a tried to use {upsert: true} and $inc but could not find the solution.

Upvotes: 1

Views: 4368

Answers (1)

turivishal
turivishal

Reputation: 36104

I have a tried to use {upsert: true} and $inc but could not find the solution

The upsert will not support in array of object, you can try 2 queries first find and second update,

Count documents using countDocuments:

let user_id = "13";
let part_id = "P456";
let hasDoc = await YourSchema.countDocuments({ user_id: user_id, "stock.part_id": part_id });
  • Check condition if document exists then increment quantity by one
  • Else push object in stock
// Document already exists, so increment it value
if (hasDoc > 0) {
  await YourSchema.updateOne(
    { user_id: user_id, "stock.part_id": part_id },
    { $inc: { "stock.$.quantity": 1 } }
  );
} 

// Document not exists then add document
else {
  await YourSchema.updateOne(
    { user_id: user_id },
    { $push: { stock: { part_id: part_id, quantity: 1 } } }
  );
}

Second Option: You can update with aggregation pipeline starting from MongoDB 4.2,

  • $cond to check if part_id is in stock
    • yes, $map to iterate loop of stock and check condition if part_id match then add 1 in quantity otherwise return current object
    • no, add new object with part_id and quantity in stock using $concatArrays
let user_id = "13";
let part_id = "P456";
db.collection.update(
  { user_id: user_id },
  [{
    $set: {
      stock: {
        $cond: [
          { $in: [part_id, "$stock.part_id"] },
          {
            $map: {
              input: "$stock",
              in: {
                $cond: [
                  { $eq: ["$$this.part_id", part_id] },
                  {
                    part_id: "$$this.part_id",
                    quantity: { $add: ["$$this.quantity", 1] }
                  },
                  "$$this"
                ]
              }
            }
          },
          { $concatArrays: ["$stock", [{ part_id: part_id, quantity: 1 }]] }
        ]
      }
    }
  }]
)

Playground

Upvotes: 6

Related Questions