Ian McInnes
Ian McInnes

Reputation: 29

mongodb push update based on ne and arrayfilters not working

I'm trying to create a patch API for a database of products in a MERN application that keeps track of expiry dates.

The idea is when a product's UPC is given, as well as the date in which it expires, the specific product is updated with the date given added to expiry dates, provided the date isn't in there already.

Sample data:

[
{
     "_id":{"$oid":"6795e982c4e5586be7dc5bfc"},
     "section":"Dairy",
     "products":
     [
          {
               "productUPC":"068700115004",
               "name":"Dairyland 2% Milk Carton 2L",
               "expiryDates":
               [
                    {
                         "dateGiven":"2025-01-30T00:00:00.000-06:00",
                         "discounted":true
                    }
               ]
          },
          {
               "productUPC":"068700011825",
               "name":"Dairyland 1% Milk Carton 2L",
               "expiryDates":[
               ]
          }
     ]
}
]

The following is the node for the patch API:

router.patch("/products/:productUPC&:expiryDate", async (req, res) => {
    try {
        let collection = await db.collection("storeSections");
        let result = await collection.updateOne({
          "products.expiryDates.dateGiven": {
            $ne: new Date(moment(req.params.expiryDate)).toISOString(true)
          }
          },
          {
            $push: {
              "products.$[x].expiryDates": {
                "dateGiven": new Date(moment(req.params.expiryDate)).toISOString(true),
                "discounted": false
              }
            }
          },
          {
            arrayFilters: [
              {
                "x.productUPC": req.params.productUPC
              }
            ]
          })
          
        res.send(result).status(200);
    } catch(err) {
        console.error(err);
        res.status(500).send("Error updating record.");
    }
});

And here is a sample patch that I sent with Postman:

localhost:5050/record/products/productUPC=068700115004&expiryDate=2025-02-21

The update worked just fine in a mongoDB playground... why isn't it working now?

Upvotes: 0

Views: 41

Answers (1)

Joe
Joe

Reputation: 28366

updateOne will match a single document, and then apply the noted updates.

In the noted query it will match the first document where "products.expiryDates.dateGiven" does not equal the provided date, regardless of the values of any other fields, and then apply the $push with the $arrayFilter.

To see which document the update is trying to affect, try running:

         findOne({
          "products.expiryDates.dateGiven": {
            $ne: new Date(moment(req.params.expiryDate)).toISOString(true)
          }})

To make sure the document being operation on actually contains that UPC, add it to the match criteria:

         .updateOne({
              "products.expiryDates.dateGiven": {
                $ne: new Date(moment(req.params.expiryDate)).toISOString(true)
              },
              "products.productUPC": req.params.productUPC
         })

If you need to make sure that it is that UPC's expiryDate that is checked, use $elemMatch:

        .updateOne({
          "products":{$elemMatch:{
                "expiryDates.dateGiven": {
                   $ne: new Date(moment(req.params.expiryDate)).toISOString(true)
                   },
                "productUPC": req.params.productUPC
         })

Upvotes: 0

Related Questions