$pulll one item from array removes the whole nested array

I have followed the online documentation to pull an item from an array and looked through the threads but I can’t find the solution to this problem. I’m trying to pull an item from a nested array, but it removes the nested arrays instead of just the single element. Can some one please explain this behaviour? and the potential solution. Thanks in advance.

await client.db("VsteamEdu").collection("leads").updateMany(  
    { },
    {
        $pull:
            {
            bookings:
                {
                    allEventDates: { $elemMatch: { "dayBookingRef": { $eq: "000117-D4"} } }
                }
            }
    })

Small sample of data:

   {
       bookings: [ {
                allEventDates: [
                    {
                        dayBookingRef: "000117-D3"
                    },
                    {
                        dayBookingRef: "000117-D4"
                    }
                ]
          } ]
     }

I found a work around using the code below. I’m still not sure why the code earlier removes the whole array. It would be great if some can explain.

    await client.db("VsteamEdu").collection("LeadsCopy").updateOne(  
    { "bookings.allEventDates.dayBookingRef": "000117-D6" },
    {
        $pull:
            {
                "bookings.$.allEventDates": {
                    "dayBookingRef": "000117-D6"
           }      
        }   
    })

Hi @VSTEAM_Education

Can you add a reproducible example for the original (first) query https://mongoplayground.net so we can run it?

Hi

I have modelled the same behaviour on the playground. Please see the link below. As you can see it returns an empty array. Please let me know what is wrong with my original code. Thanks again.

Code in play ground is below:

Configuration:

[
  {
    bookings: [
      {
        allEventDates: [
          {
            dayBookingRef: "000127-D6"
          },
          {
            dayBookingRef: "000127-D5"
          }
        ]
      }
    ]
  },
  {
    "key": 2
  }
]

Query:

db.collection.update({
  "_id": ObjectId("5a934e000102030405000000")
},
{
  $pull: {
    bookings: {
      allEventDates: {
        $elemMatch: {
          "dayBookingRef": {
            $eq: "000127-D6"
          }
        }
      }
    }
  }
})

Result:

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "bookings": []
  },
  {
    "_id": ObjectId("5a934e000102030405000001"),
    "key": 2
  }
]

Thanks,

Vidura

1 Like

The problem

I think the reason here is that $pull is removing an array element from bookings field:

The signature of this update operator is

{ $pull: { <field1>: <value|condition>, ... } }

field1 is where it removes from, and it must point to an array.

See the Docs, at this section. for an example of what I just said (why It didn’t work.)

Solutions and ideas

So for internal fields, we use dot notation, in place of the field1 of the notation above.

It is important to note how MDB interprets dot notation, which I still get wrong sometimes.

See Takeaways
  • MongoDB uses the dot notation to access the elements of an array and to access the fields of an embedded document.
  • a.b searches for
    • field in subdocument-item if b is a string
    • that index array item if a number, for example a.0: "hello"

It follows that if we want to update a field with an array of documents we would end up with a.0.b for updating the first element (document) in the array a.0 with a field b

If we want to loop, we can specify the “magic index $” and replace a.0.b for a.$.b.

If we want to update not just one array item but all that match, we use a.$[].b:

Code example ``` db.collection.update({}, { "$pull": { "bookings.$[].allEventDates": { "dayBookingRef": "000117-D3" } } }) ```

Using $ will stop after removing a single element matching the condition, this one does it for all.

Misc.

I didn’t really expect or really knew this, but $ will fail if the query does not store the field we search for.

Hi

Sorry for the delayed reply and thank you for the detailed explanation. Much appreciated.

Regards,

Vidura