0

I'm trying to pull one or multiple objects from an array and I noticed something odd.

Let's take the following document.

{
    "_id" : UUID("f7e80c8e-6b4a-4741-95a3-2567cccf9e5f"),
    "createdAt" : ISODate("2021-07-19T17:07:28.499Z"),
    "description" : null,
    "externalLinks" : [ 
        {
            "id" : "ZV8xMjM0NQ==",
            "type" : "event"
        }, 
        {
            "id" : "cF8xMjM0NQ==",
            "type" : "planning"
        }
    ],
    "updatedAt" : ISODate("2021-07-19T17:07:28.499Z")
}

I wrote a basic query to pull one element of externalLinks which looks like

db.getCollection('Collection').update(
  {
    _id: {
      $in: [UUID("f7e80c8e-6b4a-4741-95a3-2567cccf9e5f")]
    }
  }, {
    $pull: {
      externalLinks: {
        "type": "planning",
        "id": "cF8xMjM0NQ=="
      }
    }
  })

And it's working fine. But it's getting trickier when I want to pull multiple element from the externalLinks. And I'm using the operator $in for that. And the strange behaviour is here :

db.getCollection('Collection').update(
  {
    _id: {
      $in: [UUID("f7e80c8e-6b4a-4741-95a3-2567cccf9e5f")]
    }
  }, {
    $pull: {
      externalLinks: {
        $in: [{
          "type": "planning",
          "id": "cF8xMjM0NQ=="
        }]
      }
    }
  })

And this query doesn't work. The solution is to switch both field from externalLinks and do something like :

$in: [{
  "id": "cF8xMjM0NQ==",
  "type": "planning" 
}]

I tried multiple things like : $elemMatch, $positioning but it should be possible to pull multiple externalLinks. I also tried the $and operator without success.

I could easily iterate over the externalLinks to update but it'd be too easy.

And it's tickling my brain to choose that solution.

Any help would be appreciate, thank you !

1 Answer 1

1

Document fields have order, and MongoDB compares documents based on the order of the fields see here, so what field you put first matters.

After MongoDB 4.2 we can also do pipeline updates, that can be sometimes bigger, but they are much more powerful, and feels more like programming. (less declarative and pattern matching)

This doesn't mean that you need pipeline update in your case but check this way also.

Query

  • pipeline update
  • filter and keep members that the condition doesn't exist

Test code here

db.collection.update(
{_id: {$in: ["f7e80c8e-6b4a-4741-95a3-2567cccf9e5f"]}},
[{"$set": 
   {"externalLinks": 
     {"$filter": 
       {"input": "$externalLinks",
        "cond": 
        {"$not": 
         [{"$and": 
           [{"$eq": ["$$this.id", "ZV8xMjM0NQ=="]},
            {"$eq": ["$$this.type", "event"]}]}]}}}}}])
Sign up to request clarification or add additional context in comments.

1 Comment

That's perfect, I changed the code a little bit to add multiple externalLinks to filter on the pull, I changed the $and operator with a $or and it's working like a charm.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.