skip to Main Content

Does anyone know how to add an array element to a mongodb array and set a "virtual" order to the size of the array, all in an atomic operation?

So, something like:

db.users.updateOne(
    { _id: 1},
    { $addToSet: { images: {name: 'new image', order: "size of the array"} } }
)

The idea is to always have the last array element added have an order that is last.

Update:

Data before op:

{
  _id: 1, 
  images: [
    { name: 'some name', order: 0 }
  ]
}

Data after op:

{
  _id: 1, 
  images: [
    { name: 'some name', order: 0 }, 
    { name: 'new image', order: 1 }
  ]
}

Thank you!

2

Answers


  1. Assuming your order field would be an integer field, you can use $let to compute the next order number and use $concatArrays to append it to the end of the array.

    Some scenarios:

    1. images already has data in it: $max will get the largest order number, $add 1 to it.
    2. images is an empty array: the $max result will fallback to 0 due to $ifNull
    3. images.order is not perfectly 0-th ordered: it may have some gaps in between, or not starting from 0. It will be handled by $max and $add 1 logic.
    4. images is a null field or does not exists: it will be safeguarded by $ifNull and fall back to an empty array.
    db.collection.update({},
    [
      {
        "$set": {
          "images": {
            "$let": {
              "vars": {
                "seq": {
                  "$ifNull": [
                    {
                      "$add": [
                        {
                          "$max": "$images.order"
                        },
                        1
                      ]
                    },
                    0
                  ]
                }
              },
              in: {
                "$concatArrays": [
                  {
                    "$ifNull": [
                      "$images",
                      []
                    ]
                  },
                  [
                    //your payload here
                    {
                      "name": "new image",
                      "order": "$$seq"
                    }
                  ]
                ]
              }
            }
          }
        }
      }
    ],
    {
      multi: true
    })
    

    Mongo Playground

    Login or Signup to reply.
  2. Note that you already keep your image details in an array, so they already have an order defined by the position in the array. So if the motivation for the order attribute is to query the array index later, there are other ways to do that, and it may be redundant.

    For example, the $unwind operator optionally returns an array index. You could query this instead of a custom field which needs to be separately maintained every time the images field is updated.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search