MongoDB $replaceOne

The $replaceOne aggregation pipeline operator was introduced in MongoDB 4.4.

This operator replaces the first instance of a search string in an input string with a replacement string and returns the result.

If the search string isn’t found, then $replaceOne returns the input string.

Example

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

{
	"_id" : 1,
	"product" : "Left Handed Screwdriver with Left Handed Carry Case"
}

Let’s use the $replaceOne operator to replace the first instance of the string Left Handed with another string:

db.products.aggregate([
   {
     $project:
      {
         product: { $replaceOne: { input: "$product", find: "Left Handed", replacement: "Ambidextrous" } }
      }
   }
]).pretty()

Result:

{
	"_id" : 1,
	"product" : "Ambidextrous Screwdriver with Left Handed Carry Case"
}

Notice that there are actually two instances of the search string (Left Handed) but only the first instance was replaced.

To replace all instances, use the $replaceAll operator.

Case Sensitivity

The $replaceOne operator is case sensitive.

Example:

db.products.aggregate([
   {
     $project:
      {
         product: { $replaceOne: { input: "$product", find: "Left handed", replacement: "Ambidextrous" } }
      }
   }
]).pretty()

Result:

{
	"_id" : 1,
	"product" : "Left Handed Screwdriver with Left Handed Carry Case"
}

In this case, I changed the case of a single character in my search string. I changed Handed to handed. This resulted in the search string not being found and so nothing was replaced. Therefore, the input string was returned.

Diacritic Sensitivity

The $replaceOne operator is diacritic sensitive.

Suppose we add the following document to our collection:

{ "_id": 2, "product": "Toupée Tape" }

And now let’s try to search and replace the word Toupée, but forget to use the acute accent:

db.products.aggregate([
    { $match: { _id: 2 } },
   {
     $project:
      {
         product: { $replaceOne: { input: "$product", find: "Toupee", replacement: "Wig" } }
      }
   }
])

Result:

{ "_id" : 2, "product" : "Toupée Tape" }

No change.

I didn’t include the diacritic in my search string and so there was no match.

Here it is again, but this time I include the diacritic:

db.products.aggregate([
    { $match: { _id: 2 } },
   {
     $project:
      {
         product: { $replaceOne: { input: "$product", find: "Toupée", replacement: "Wig" } }
      }
   }
])

Result:

{ "_id" : 2, "product" : "Wig Tape" }

This time the search string was found and replaced.

Null Expressions

If any of the expressions provided to $replaceOne are null, the result is null.

Here’s an example of providing a null operator field to $replaceOne:

db.products.aggregate([
   {
     $project:
      {
         product: { $replaceOne: { input: "$product", find: null, replacement: "Ambidextrous" } }
      }
   }
]).pretty()

Result:

{ "_id" : 1, "product" : null }
{ "_id" : 2, "product" : null }

In this case the find operator field was null and so the result was null.

Missing Fields

If the input or find operator fields refer to a field that doesn’t exist, then the result is null.

Example:

db.products.aggregate([
   {
     $project:
      {
         product: { $replaceOne: { input: "$oops", find: "Left Handed", replacement: "Ambidextrous" } }
      }
   }
]).pretty()

Result:

{ "_id" : 1, "product" : null }
{ "_id" : 2, "product" : null }

Non-String Values

All expressions provided to $replaceOne must evaluate to a string or null. Providing any other type returns an error.

Suppose we add the following document to our collection:

{ "_id" : 3, "product" : "Long Weight", "price" : NumberDecimal("7.50") }

Let’s try to do a search and replace on the price field:

db.products.aggregate([
   {
     $project:
      {
         product: { $replaceOne: { input: "$price", find: "7.50", replacement: "10.50" } }
      }
   }
])

Result:

Error: command failed: {
	"ok" : 0,
	"errmsg" : "$replaceOne requires that 'input' be a string, found: 7.50",
	"code" : 51746,
	"codeName" : "Location51746"
} : aggregate failed :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:18:14
_assertCommandWorked@src/mongo/shell/assert.js:618:17
assert.commandWorked@src/mongo/shell/assert.js:708:16
DB.prototype._runAggregate@src/mongo/shell/db.js:266:5
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1046:12
@(shell):1:1

It returns an error, as expected.

Unicode Normalisation

The $replaceOne operator does not perform any unicode normalisation.

See the MongoDB documentation for more information about this, and an example.