Increment and update a new array element in updates

Hi,

Below is the data structure in orders collections

    {"_id": "order1", 
    "status": "pending",
    "lineitems": 
      [
          {"version": 1, "value": ISODate()},
          {"version": 2, "value": ISODate()},
          {"version": 3, "value": ISODate()},
     ]
    },

    {"_id": "order2",
    "status": "pending",
     "lineitems": 
      [
          {"version": 1, "value": ISODate()},
          {"version": 2, "value": ISODate()},
     ]
    },

    {"_id": "order3",
    "status": "completed",
     "lineitems": 
      [
          {"version": 1, "value": ISODate()},
     ]
    },

    {"_id": "order4",
    "status": "pending",
     "lineitems": 
      [
          {"version": 1, "value": ISODate()},
     ]
    },

I have two queries,

  1. Remove the last element using $pop from lineitems only when the array size is greater than 1.
    – I tried adding validators using $jsonschema to ensure that the array has minimum size of 1.

db.orders.updateMany({“status”:“pending”},{“$pop”: {“lineitems”: -1}});

$pop failed with document validation error for order4. Is there anyway to flag order4 and do $pop on rest of the documents where lineitems size is greater than 1? Or is there an alternate option available?

  1. How do I target documents with status = “pending” in order collection and update line items array with new element depending on the size of the array within the document
        {"_id": "order1", 
        "status": "pending",
        "lineitems": 
          [
              {"version": 1, "value": ISODate()},
              {"version": 2, "value": ISODate()},
              {"version": 3, "value": ISODate()},
              **{"version": 4, "value": ISODate()}** -- To Update. version will be the max of the array size within the document. 
         ]
        },

        {"_id": "order2",
        "status": "pending",
         "lineitems": 
          [
              {"version": 1, "value": ISODate()},
              {"version": 2, "value": ISODate()},
              **{"version": 3, "value": ISODate()}**, -- To Update

         ]
        },


        {"_id": "order4",
        "status": "pending",
         "lineitems": 
          [
              {"version": 1, "value": ISODate()},
              **{"version": 2, "value": ISODate()},** -- To Update
         ]
        },
```

Mongo version: 4.2

Simply replace your query from

{"status":"pending"}
to
{ "status":"pending" , "lineitems.1" : { "$exists" : true } }

As for Q2, I have bookmarked your post for later as it needs more thinking.

1 Like

Thanks for the pointers @Steeve, this is helpful. One more additional question related to the same subject, $jsonSchema does restrict the insert/updates for all documents even if one of the document fails during document validation stage? (or) is this specific to the version (4.2) I’m using ?

Q2, is very much inclined with data modelling. I opted for Document versioning model as suits my requirement but updates as mentioned above seems to be a challenge.

1 Like

As for Q2, your comment

indicates to me that you version attribute is redundant and useless (just like my previous word B-) without seeing your use-case. It’s value will always be index+1. And like you mentioned

For example, if you want version:2, you would do:

c.aggregate( { "$project" : { v2 : { "$arrayElemAt" : [ "$lineitems" , 1 ]}}})

Which would give the following result on the documents you shared:

[ { _id: 'order1',
    v2: 
     { version: 2,
       value: Mon Nov 22 2021 08:53:03 GMT-0500 (heure normale de l’Est nord-américain) } },
  { _id: 'order2',
    v2: 
     { version: 2,
       value: Mon Nov 22 2021 08:53:03 GMT-0500 (heure normale de l’Est nord-américain) } },
  { _id: 'order3' },
  { _id: 'order4' } ]