1

Disclaimer: I made a very simple minimal failing example here, but what I'm trying to achieve is in a more complicated context, and it's very important that the document can be modified atomically.

Let's say I have documents representing buildings. Each building has a list of floors (the "floors" array in the document).

[
  {
    _id: "DcGvSbWmOH46Dhu9O",
    floors: [
      {
        index: 0
      },
      {
        index: 1
      },
      {
        index: 2
      },
      {
        index: 3
      },
      {
        index: 4,
        cafeteria: true
      }
    ]
  }
]

In this example, there is a cafeteria at floor 4 (indicated by the field "cafeteria" set to true).

The cafeteria has closed so I'd like to remove it from the 4th floor.

Here is my attempt:

db.collection.update(
  { _id: "DcGvSbWmOH46Dhu9O" },
  {
    $unset: {
      "floors.$[element].cafeteria": ""
    }
  },
  {
    arrayFilters: [
      {
        "element": {
          "index": 4
        }
      }
    ]
  }
)

When executed, no change happens, the element at index 4 still has the cafeteria. You can see this in mongoplayground: https://mongoplayground.net/p/mv8nUFhWSTY

Even trying to set "cafeteria" to false instead of just removing the key fails in the same way.

db.collection.update(
  { _id: "DcGvSbWmOH46Dhu9O" },
  {
    $set: {
      "floors.$[element].cafeteria": false
    }
  },
  {
    arrayFilters: [
      {
        "element": {
          "index": 4
        }
      }
    ]
  }
)

No change (mongoplayground link: https://mongoplayground.net/p/LyeaHeU0CQF )

Adding a field that didn't existed before works, but removing an existing field or removing it doesn't work. What's happening?

By the way, I made a very simple minimal failing example here, but what I'm trying to achieve is in a different context, and it's very important that the document can be modified atomically (I want to avoid reading the document, computing a new version and sending it to Mongo, this would cause race conditions issues in multiple parts of my application).

5
  • 2
    Change the array filters to: { "element.index": 4 }: mongoplayground.net/p/eXplS5p3g1d Commented Mar 9 at 17:14
  • Well, thanks, it works that way indeed. But it is very weird because using { "element": { "index": 4}} does work when adding a NEW field using $set. Here is an example: mongoplayground.net/p/fh_o-0YimoS Commented Mar 9 at 17:18
  • 1
    Or with $ positional operator like this or like this if only affecting one array element as opposed to using arrayFilters Commented Mar 9 at 20:30
  • 1
    Thanks, I didn't know you could do that. I'll probably use that syntax. I still don't understand why the syntax I used in my post arrayFilters: [{ "element": { "index": 4}}] works to add a new field to an element of an array, but doesn't work when you try to remove a field or modify an existing field. When reading the documentation about arrayFilters, it seems to me that all three should work. Commented Mar 9 at 22:36
  • 1
    Because you are not using path traversal in your original $unset attempt you would need to do an exact match on element. So your updated query would look like this with arrayFilters i.e match index and cafeteria as well as any other key you have in that object. Commented Mar 9 at 23:04

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.