In mongoDb, how do you remove an array element by

2019-01-01 13:37发布

问题:

{

        \"_id\" : ObjectId(\"4d1cb5de451600000000497a\"),           
        \"name\" : \"dannie\",  
        \"interests\" : [  
            \"guitar\",  
            \"programming\",           
            \"gadgets\",  
            \"reading\"  
        ]   
}

In the example above, assume the above document is in the db.people collection. How to remove the 3rd element of the interests array by it\'s index?

Edit:

This is my current solution:

var interests = db.people.findOne({\"name\":\"dannie\"}).interests;  
interests.splice(2,1)  
db.people.update({\"name\":\"dannie\"}, {\"$set\" : {\"interests\" : interests}});

Is there a more direct way?

回答1:

There is no straight way of pulling/removing by array index. In fact, this is an open issue http://jira.mongodb.org/browse/SERVER-1014 , you may vote for it.

The workaround is using $unset and then $pull:

db.lists.update({}, {$unset : {\"interests.3\" : 1 }}) 
db.lists.update({}, {$pull : {\"interests\" : null}})

Update: as mentioned in some of the comments this approach is not atomic and can cause some race conditions if other clients read and/or write between the two operations. If we need the operation to be atomic, we could:

  • Read the document from the database
  • Update the document and remove the item in the array
  • Replace the document in the database. To ensure the document has not changed since we read it, we can use the update if current pattern described in the mongo docs


回答2:

You can use $pull modifier of update operation for removing a particular element in an array. In case you provided a query will look like this:

db.people.update({\"name\":\"dannie\"}, {\'$pull\': {\"interests\": \"guitar\"}})

Also, you may consider using $pullAll for removing all occurrences. More about this on the official documentation page - http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull

This doesn\'t use index as a criteria for removing an element, but still might help in cases similar to yours. IMO, using indexes for addressing elements inside an array is not very reliable since mongodb isn\'t consistent on an elements order as fas as I know.



回答3:

Rather than using the unset (as in the accepted answer), I solve this by setting the field to a unique value (i.e. not NULL) and then immediately pulling that value. A little safer from an asynch perspective. Here is the code:

    var update = {};
    var key = \"ToBePulled_\"+ new Date().toString();
    update[\'feedback.\'+index] = key;
    Venues.update(venueId, {$set: update});
    return Venues.update(venueId, {$pull: {feedback: key}});

Hopefully mongo will address this, perhaps by extending the $position modifier to support $pull as well as $push.



回答4:

I would recommend using a GUID (I tend to use ObjectID) field, or an auto-incrementing field for each sub-document in the array.

With this GUID it is easy to issue a $pull and be sure that the correct one will be pulled. Same goes for other array operations.



回答5:

Instead of using $pull we can use $pop for removing elements in an array by its index. But you should subtract 1 from index position for removing based on the index.

For E.g if you want to remove the element in index 0 you should use -1, for index 1 you should use 0 and so on...

Query To Remove 3rd Element(gadgets):

db.people.update({\"name\":\"dannie\"}, {\'$pop\': {\"interests\": 1}})

for reference: https://docs.mongodb.com/manual/reference/operator/update/pop/



标签: mongodb