简体   繁体   中英

Update nested array of objects in mongodb with node

I am working with node and trying to update data with a date stamp in a nested array of objects. My data structure is as follows:

{
_id:629f2f5e7aa147d6503957d0
kid_id:"629f2f5e7aa147d6503957ce"
inventory: [
    { size: "0", 
      purchased: "0", 
      used: [{}], 
      _id: "111111"
     },
    { size: "1", 
      purchased: "10", 
      used: [
            { date: "06/08/22", count: "2"}
       ], 
      _id: "222222"
      }
    ]
}

I want to target size 1 and add another object to the "used" array with { date: "06/09/22", count: "4"}

Long term goal, when there is another "count" entry with existing date, just increment the count. If it is a new date that is when I need a new object in the array.

I started with the code below but this is not right:

router.put('/used', auth, async (req, res) => {
  let kidID = req.body.kid_id;
  let size = req.body.size;

  try {
    const record = await InventoryRecord.updateOne(
      { kid_id: kidID },
      { $inc: { 'inventory.$[el].used': -1 } },
      { arrayFilters: [{ 'el.size': size }] }
    );
    console.log(record);
    res.send(record);
  } catch (error) {
    res.send({ message: error.message });
  }
});

Thanks in advance for any help

You can do something like this:

  1. Find the inventory item we want to update and call it replace
  2. Split replace to two parts innerObj (the obj with date to edit) and innerOthers - rest of the array
  3. Fill innerObj in case there were no matching document.
  4. Increment the count of innerObj by 1.
  5. Merge back innerOthers and innerObj to newObj .
  6. Merge newObj into inventory .
db.collection.aggregate([
  {$addFields: {
      replace: {
        $first: {
          $filter: {
            input: "$inventory",
            as: "item",
            cond: {$eq: ["$$item.size",  inputSize]}
          }
        }
      }
    }
  },
  {$addFields: {
      innerObj: {
        $filter: {
          input: "$replace.used",
          as: "item",
          cond: {$eq: ["$$item.date", inputDate]}
        }
      },
      innerOthers: {
        $filter: {
          input: "$replace.used",
          as: "item",
          cond: {$ne: ["$$item.date", inputDate]}
        }
      },
      replace: "$$REMOVE"
    }
  },
  {$set: {
      innerObj: {
        $cond: [
          {$gt: [{$size: "$innerObj"}, 0]},
          {$first: "$innerObj"}, 
          {count: "0",  date: inputDate}
        ]
      }
    }
  },
  {$set: {"innerObj.count": {$toString: {$add: [{$toInt: "$innerObj.count"}, 1]}}}},
  {$set: {
      newObj: {$concatArrays: ["$innerOthers", ["$innerObj"]]},
      innerObj: "$$REMOVE",
      innerOthers: "$$REMOVE"
    }
  },
  {
    $set: {
      inventory: {
        $map: {
          input: "$inventory",
          as: "item",
          in: {
            $mergeObjects: [
              "$$item",
              {$cond: [
                  {$eq: ["$$item.size", inputSize]},
                  {used: "$newObj"},
                  {used: "$$item.used"}
                ]}
            ]
          }
        }
      },
      newObj: "$$REMOVE"
    }
  }
])

See how it works on the playground example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM