Search code examples
arraysjsonmongodb

How do I remove just one Element from MongoDB Array that equals a value?


I have an Array of ints in mongo db. Some of the values come up multiple times like this:

{binder : [4,7,9,7]}

I use pull on the collection like this

{ $pull: { binder: 7} }

It will remove all the 7 and I end up with:

{binder : [4,9]}

However I want to just remove one of the sevens to get something like this:

{binder : [4,7,9]}

How would I go about this. The indices of the numbers are not known and duplicates are not always on last/first spots.

After trying and searching for a long time I found a way with $indexOfArray which is not supported where I need to use it.


Solution

  • There is currently no way to only remove one item from an array, as said in the documention "The $pull operator removes from an existing array all instances of a value or values that match a specified condition."

    You can however use this work around:

    Find and unset one item from the array:

    > db.arrays.save({ s : [ 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10 ] })
    WriteResult({ "nInserted" : 1 })
    
    > db.arrays.update({ "s" : 5 }, { $unset : { "s.$" : true } })
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    

    This will give us the following

    > db.arrays.find()
    { "_id" : ObjectId("584c707f1c86f44b7300b223"), "s" : [ 1, 2, 3, 4, null, 5, 6, 7, 8, 9, 10 ] }
    

    Then we can just pull the nulls

    > db.arrays.update({ }, { $pull: { "s" : null } })
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    

    Our 5 that we remove now will be gone:

    > db.arrays.find()
    { "_id" : ObjectId("584c707f1c86f44b7300b223"), "s" : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] }
    

    It's a bit of a work around but it's pretty safe with multiple atomic operations (as long as you don't use null as a valid value)