MongoDB $pull

In MongoDB, you can use the $pull operator to remove values from an array.

Use $pull in conjunction with a method such as update() to update the specified document with the change.

Example

Suppose we have a collection called products with the following documents:

{ "_id" : 1, "prod" : "Bat", "sizes" : [ "S", "M", "XL", "XXL" ] }
{ "_id" : 2, "prod" : "Hat", "sizes" : [ "S", "L", "XL" ] }
{ "_id" : 3, "prod" : "Cap", "sizes" : [ "XS", "S", "M", "L", "XL" ] }

We can remove an element from the array in document 1 like this:

db.products.update( 
  { _id: 1 }, 
  { $pull: { sizes: "XXL" } } 
)

Output:

WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

That message tells us that one document matched and one (i.e. the same document) was modified.

Let’s take a look at the collection now:

db.products.find()

Result:

{ "_id" : 1, "prod" : "Bat", "sizes" : [ "S", "M", "XL" ] }
{ "_id" : 2, "prod" : "Hat", "sizes" : [ "S", "L", "XL" ] }
{ "_id" : 3, "prod" : "Cap", "sizes" : [ "XS", "S", "M", "L", "XL" ] }

We can see that the array in document 1 has had its value XXL removed as specified.

Remove Multiple Values

We can use the $in operator to specify multiple values that we want to remove from the array.

Example:

db.products.update( 
  { _id: 3 }, 
  { $pull: { sizes: { $in: ["XS", "XL"] } } } 
)

Output:

WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

Now let’s check the collection again:

db.products.find()

Result:

{ "_id" : 1, "prod" : "Bat", "sizes" : [ "S", "M", "XL" ] }
{ "_id" : 2, "prod" : "Hat", "sizes" : [ "S", "L", "XL" ] }
{ "_id" : 3, "prod" : "Cap", "sizes" : [ "S", "M", "L" ] }

We can see that the two specified elements have been removed from the array in document 3.

Update All Documents

You can add multi: true or use the updateMany() method to update all documents that match the criteria.

When you do this, remove any selection criteria from the first query document (that specifies which document/s to update). In other words, use an empty document as the first argument to the update() (or updateMany()) method.

Example:

db.products.update( 
  { }, 
  { $pull: { sizes: "XL" } },
  { multi: true }
)

Output:

WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 2 })

In this case, we can see that three documents matched (because there are three documents in the collection), but only two were modified (because only two had the value XL in the sizes array).

And recheck the collection:

db.products.find()

Result:

{ "_id" : 1, "prod" : "Bat", "sizes" : [ "S", "M" ] }
{ "_id" : 2, "prod" : "Hat", "sizes" : [ "S", "L" ] }
{ "_id" : 3, "prod" : "Cap", "sizes" : [ "S", "M", "L" ] }

We can see that all instances of XL have been removed from all documents in the collection.

Array of Documents

If you have array that contain documents as their elements, you can remove any of those documents by specifying criteria that matches data within the document.

Suppose we have a collection called restaurants that the following documents:

{
	"_id" : 1,
	"name" : "The Rat",
	"reviews" : [
		{
			"name" : "Stanley",
			"date" : "04 December, 2020",
			"ordered" : "Dinner",
			"rating" : 1
		},
		{
			"name" : "Tom",
			"date" : "04 October, 2020",
			"ordered" : "Lunch",
			"rating" : 2
		}
	]
}
{
	"_id" : 2,
	"name" : "Yum Palace",
	"reviews" : [
		{
			"name" : "Stacey",
			"date" : "08 December, 2020",
			"ordered" : "Lunch",
			"rating" : 3
		},
		{
			"name" : "Tom",
			"date" : "08 October, 2020",
			"ordered" : "Breakfast",
			"rating" : 4
		}
	]
}
{
	"_id" : 3,
	"name" : "Boardwalk Cafe",
	"reviews" : [
		{
			"name" : "Steve",
			"date" : "20 December, 2020",
			"ordered" : "Breakfast",
			"rating" : 5
		},
		{
			"name" : "Lisa",
			"date" : "25 October, 2020",
			"ordered" : "Dinner",
			"rating" : 5
		},
		{
			"name" : "Kim",
			"date" : "21 October, 2020",
			"ordered" : "Dinner",
			"rating" : 5
		}
	]
}

In this case, the field called reviews contains an array of documents. Each document is a different review of the restaurant in question.

We could use $pull to remove reviews that match a certain criteria.

Example:

db.restaurants.update(
  { },
  { $pull: { reviews: { rating: { $lt: 4 } } } },
  { multi: true }
)

Output:

WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 2 })

This message tells us that three documents matched the query criteria (because we selected all documents), and two documents were modified (because two matched our $pull criteria).

Let’s check the collection again to see the effect:

db.restaurants.find().pretty()

Result:

{ "_id" : 1, "name" : "The Rat", "reviews" : [ ] }
{
	"_id" : 2,
	"name" : "Yum Palace",
	"reviews" : [
		{
			"name" : "Tom",
			"date" : "08 October, 2020",
			"ordered" : "Breakfast",
			"rating" : 4
		}
	]
}
{
	"_id" : 3,
	"name" : "Boardwalk Cafe",
	"reviews" : [
		{
			"name" : "Steve",
			"date" : "20 December, 2020",
			"ordered" : "Breakfast",
			"rating" : 5
		},
		{
			"name" : "Lisa",
			"date" : "25 October, 2020",
			"ordered" : "Dinner",
			"rating" : 5
		},
		{
			"name" : "Kim",
			"date" : "21 October, 2020",
			"ordered" : "Dinner",
			"rating" : 5
		}
	]
}

We can see that only reviews with a rating of 4 and above remain. All reviews less than 4 have been removed.