How to safely swap values of two objects in array in one request?

danefondo

I'm storing the order of items in a specific context and want to allow changing the order of the items.

Example document:

{
 _id: docID,
 items: [
     {
         _id: 1,
         orderNr: 0,
     },
     {
         _id: 2,
         orderNr: 1,
     },
     {
         _id: 3,
         orderNr: 2,
     },
 ]
}

Solutions I could think of:

The 'brute' way to do this would be to find the document, change the array with JavaScript and use $set to swap the entire array. This seems unsafe.

The other way I thought of was using arrayFilters and using data from the client. This seems safe, since the array filters require that each item still has its old orderNr value, however it requires knowing the current orderNr. Example:

collection.findOneAndUpdate(
        { _id: new ObjectID(item1Data.contextID), "items._id": new ObjectID(item1Data._id) },
        {
          $set: {
            "items.$[item1].orderNr": item2Data.orderNr,
            "items.$[item2].orderNr": item1Data.orderNr,
          },
        },
        {
          arrayFilters: [
            { "item1._id": item1Data._id, "item1.orderNr": item1Data.orderNr },
            { "item2._id": item2Data._id, "item2.orderNr": item2Data.orderNr },
          ],
        }
      );

Is there a way I could just use the ID of both items to swap their orderNr values, without having to know the current orderNr from the client or from an extra request — using existing values straight from the document, during the request and just using ID to swap?

Tom Slabbaert

Yes it's possible, you want to be using the aggregation pipeline updates framework, this will allow you to use aggregation expressions within your update body.

At this point you can achieve this update in multiple different ways, here is one way which I think is the most "readable". Essentially we iterate over all items using $map, and if the documents match based on the id we convert them:

const item1Data = { _id: 1 };
const item2Data = { _id: 3};

db.collection.update({},
[
  {
    $set: {
      item1: {
        $arrayElemAt: [
          {
            $filter: {
              input: "$items",
              cond: {
                $eq: [
                  "$$this._id",
                  item1Data._id
                ]
              }
            }
          },
          0
        ]
      },
      item2: {
        $arrayElemAt: [
          {
            $filter: {
              input: "$items",
              cond: {
                $eq: [
                  "$$this._id",
                  item2Data._id
                ]
              }
            }
          },
          0
        ]
      }
    }
  },
  {
    "$set": {
      items: {
        $map: {
          input: "$items",
          in: {
            $switch: {
              branches: [
                {
                  case: {
                    $eq: [
                      "$$this._id",
                      item1Data._id
                    ]
                  },
                  then: {
                    $mergeObjects: [
                      "$$this",
                      {
                        orderNr: "$item2.orderNr"
                      }
                    ]
                  }
                },
                {
                  case: {
                    $eq: [
                      "$$this._id",
                      item2Data._id
                    ]
                  },
                  then: {
                    $mergeObjects: [
                      "$$this",
                      {
                        orderNr: "$item1.orderNr"
                      }
                    ]
                  }
                }
              ],
              default: "$$this"
            }
          }
        }
      }
    }
  },
  {
    $unset: [
      "item1",
      "item2"
    ]
  }
])

Mongo Playground

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How to "swap" two values in an array?

how swap between two array values?

Merge two array values into one array of objects

How to swap two objects in Java?

How to combine two array of objects into one array based on key match values

How can I swap two elements in one array?

How to join two arrays into one array of objects

How to combine two arrays into one array of objects?

How to filter on two values in an array of objects in Jsonata?

How to get values from one array of objects into another array of objects

Efficient way to swap property values in array of objects

Merge two array of objects into one by given key and duplicating other values

How to swap values of an array? Javascript

How to sort an array of objects by one of the objects string values numerically?

How to assign values one by one from an array of objects?

How to swap two objects' positions on a tkinter canvas

How to merge two array of objects in one big array

TS: how to merge values in an array of objects into one array

How to convert array with objects to one object like Laravel Request object

Filter two values in array of objects

How does one swap two panes in Tmux?

How to swap the values in two columns in R?

How to merge ith values of two different array in one array python

Grouping values into one array of objects from two objects based on differing keys

How to merge two objects (associative array) with same key into one object

How to merge two matching objects from different array into one object?

How to convert two arrays of same length into one array of objects in javascript?

how to merge two and more array of objects in one with unique keys

How can I merge two array of objects and concatenate values?

TOP Ranking

HotTag

Archive