MongoDB C# docs
GitHub.NET DriverMongoDB docs
  • ⭐Introduction
  • πŸ“ŒGetting started
    • Environment setup
    • πŸƒβ€β™‚οΈ Quick start
      • MongoDB connection
      • Databases
      • Collections
      • Insert documents
      • Read documents
      • Update documents
  • πŸ“‘CRUD Basics
    • βž•Create
      • Id Member
      • Ordered insert
    • πŸ”ŽRead
      • Basics
      • Comparison Operators
      • Logical Operators
      • Element Operators
      • Array operators
      • Evaluation Operators
    • πŸ“Update
      • Operators
      • Replace
      • Arrays
    • ❌Delete
  • πŸ§ͺAggregation
    • Overview
    • βœ‚οΈProject
    • 🎯Match
    • πŸ“¦Group
    • 🚩Unwind
    • ⏩Pagination
    • πŸ“ˆBucket
    • ✨Operators
Powered by GitBook
On this page
  • ReplaceOne
  • Upsert
  • FindOneAndReplaceOne
  1. CRUD Basics
  2. Update

Replace

PreviousOperatorsNextArrays

Last updated 5 years ago

ReplaceOne

You can replace a single document entirely by using the ReplaceOne method on an IMongoCollection<T>.

IMongoCollection<T>
    .ReplaceOne(FilterDefinition<T> filter, T document)

The sample replaces the first document with a new one.

ReplaceDocuments.cs
var collection = database
    .GetCollection<User>(Constants.UsersCollection);

// this is the new document - demo only
var newUser = RandomData.GenerateUsers(1).First();

// replace the first document in the collection
var replaceOneResult = await collection
    .ReplaceOneAsync(Builders<User>.Filter.Empty, newUser);
var bsonCollection = database
            .GetCollection<BsonDocument>(Constants.UsersCollection);

// this is the new document - demo only
var newUser = RandomData.GenerateUsers(1).First();

var bsonReplaceOneResult = await bsonCollection
    .ReplaceOneAsync(new BsonDocument(), 
                newUser.ToBsonDocument());
db.users.replaceOne({},
{
	"gender" : 1,
	"firstName" : "Chris",
	"lastName" : "Sakellarios",
	"userName" : "Elsie.VonRueden72",
	"avatar" : "https://s3.amazonaws.com/uifaces/faces/twitter/miguelmendes/128.jpg",
	"email" : "Elsie.VonRueden@yahoo.com",
	"dateOfBirth" : ISODate("1965-08-26T15:55:31.907+02:00"),
	"address" : {
		"street" : "8902 Baumbach Burg",
		"suite" : "Apt. 717",
		"city" : "West Carlieton",
		"state" : "South Carolina",
		"zipCode" : "85642-3703",
		"geo" : {
			"lat" : -69.6681,
			"lng" : -116.3583
		}
	},
	"phone" : "(222) 443-5341 x35825",
	"website" : "https://github.com/chsakell",
	"company" : {
		"name" : "Abshire Inc",
		"catchPhrase" : "Function-based mission-critical budgetary management",
		"bs" : "monetize holistic eyeballs"
	},
	"salary" : 2482,
	"monthlyExpenses" : 2959,
	"favoriteSports" : [
		"Basketball",
		"Baseball",
		"Table Tennis",
		"Ice Hockey",
		"Handball",
		"Formula 1",
		"American Football"
	],
	"profession" : "Model"
})

--------------------------- 
        
// sample update result
{
	"acknowledged" : true,
	"matchedCount" : 1,
	"modifiedCount" : 1
}
public class User
{
    [BsonId]
    [BsonIgnoreIfDefault] // required for replace documents 
    public ObjectId Id { get; set; }
    public Gender Gender { get; set; }
    public string FirstName {get; set; }
    public string LastName {get; set; }
    public string UserName {get; set; }
    public string Avatar {get; set; }
    public string Email {get; set; }
    public DateTime DateOfBirth {get; set; }
    public AddressCard Address {get; set; }
    public string Phone {get; set; }
    
    [BsonIgnoreIfDefault]
    public string Website {get; set; }
    public CompanyCard Company {get; set; }
    public decimal Salary { get; set; }
    public int MonthlyExpenses { get; set; }
    public List<string> FavoriteSports { get; set; }
    public string Profession { get; set; }
}

The identifier field _id on the new document must fulfill one of the following conditions:

  • If specified, must be equal to the current document's value

  • Not specified at all. MongoDB will create a new one automatically

In case you do set a value for the identifier _id field and it's different than the current one, you will get the exception:After applying the update, the (immutable) field '_id' was found to have been altered to _id: <new-id>

One common scenario where you need to replace documents is when you want to move fields inside the documents. Consider that you have the following document.

{
        "_id" : ObjectId("5ea55f572109b8cadfc146e9"),
        "username" : "chsakell",
        "friends" : [
                "John",
                "Maria",
                "Catherine"
        ],
        "blocked" : [
                "Jake",
                "Helen"
        ]
}

The following sample moves friends and blocked top level fields in a new embedded document field named relationships.

ReplaceDocuments.cs
var socialAccountAfter = new SocialAccount
{
    Username = username,
    RelationShips = new RelationShips
    {
        Friends = friends,
        Blocked = blocked
    }
};

await socialNetworkCollection
    .ReplaceOneAsync(Builders<SocialAccount>.Filter
        .Eq(ac => ac.Username, username), socialAccountAfter);
        
{
        "_id" : ObjectId("5ea55f572109b8cadfc146e9"),
        "username" : "chsakell",
        "relationShips" : {
                "friends" : [
                        "John",
                        "Maria",
                        "Catherine"
                ],
                "blocked" : [
                        "Jake",
                        "Helen"
                ]
        }
public class SocialAccount
{
    [BsonIgnoreIfDefault]
    public ObjectId Id { get; set; }
    public string Username { get; set; }
    public RelationShips RelationShips { get; set; }
}

public class RelationShips
{
    public List<string> Friends { get; set; }
    public List<string> Blocked { get; set; }
}

When replacing a document make sure to be precise 🎯 on your filter, otherwise you might get a E11001 duplicate key on update error. For example, in the previous sample if the socialAccountAfter object already contained the _id value and there were more than one documents with username "chsakell" you would get the error. Why? Because MongoDB would try to set in more than one documents the same _id unique identifier value.

Upsert

If the filter in the ReplaceOne operation fails to match a document then nothing happens in the database. You can change this behavior by passing a replace options argument to the replace operation and setting upsert = true.

IMongoCollection<T>
    .ReplaceOne(FilterDefinition<T> filter, 
                T document, 
                ReplaceOptions options)

The sample tries to replace a user document that has company name "Microsoft Corp". If it finds a match then it will replace it with the microsoftCeo document but if it doesn't, it will insert it.

ReplaceDocuments.cs
var collection = database
    .GetCollection<User>(Constants.UsersCollection);

// this is the new document - demo only
var microsoftCeo = RandomData.GenerateUsers(1).First();
            microsoftCeo.FirstName = "Satya";
            microsoftCeo.LastName = "Nadella";
            microsoftCeo.Company.Name = "Microsoft";

// replace the first document in the collection
var addOrReplaceSatyaNadellaResult = await collection
    .ReplaceOneAsync<User>(u => u.Company.Name == "Microsoft Corp",
        microsoftCeo, new ReplaceOptions()
        {
            IsUpsert = true
        });
var bsonCollection = database
      .GetCollection<BsonDocument>(Constants.UsersCollection);

// this is the new document - demo only
// this is the new document - demo only
var microsoftCeo = RandomData.GenerateUsers(1).First();
            microsoftCeo.FirstName = "Satya";
            microsoftCeo.LastName = "Nadella";
            microsoftCeo.Company.Name = "Microsoft";

var bsonAddOrReplaceSatyaNadellaUser = await bsonCollection
    .FindOneAndReplaceAsync(
        Builders<BsonDocument>.Filter.Eq("company.name", "Microsoft Corp"), 
            microsoftCeo.ToBsonDocument(), 
        new FindOneAndReplaceOptions<BsonDocument>()
    {
        IsUpsert = true,
        ReturnDocument = ReturnDocument.After
    });
db.users.replaceOne({ "company.name": "Microsoft Corp"},
{
	"gender" : 1,
	"firstName" : "Chris",
	"lastName" : "Sakellarios",
	"userName" : "Elsie.VonRueden72",
	"avatar" : "https://s3.amazonaws.com/uifaces/faces/twitter/miguelmendes/128.jpg",
	"email" : "Elsie.VonRueden@yahoo.com",
	"dateOfBirth" : ISODate("1965-08-26T15:55:31.907+02:00"),
	"address" : {
		"street" : "8902 Baumbach Burg",
		"suite" : "Apt. 717",
		"city" : "West Carlieton",
		"state" : "South Carolina",
		"zipCode" : "85642-3703",
		"geo" : {
			"lat" : -69.6681,
			"lng" : -116.3583
		}
	},
	"phone" : "(222) 443-5341 x35825",
	"website" : "https://github.com/chsakell",
	"company" : {
		"name" : "Abshire Inc",
		"catchPhrase" : "Function-based mission-critical budgetary management",
		"bs" : "monetize holistic eyeballs"
	},
	"salary" : 2482,
	"monthlyExpenses" : 2959,
	"favoriteSports" : [
		"Basketball",
		"Baseball",
		"Table Tennis",
		"Ice Hockey",
		"Handball",
		"Formula 1",
		"American Football"
	],
	"profession" : "Model"
}, { upsert: true })

--------------------------- 
        
// sample update result
{
	"acknowledged" : true,
	"matchedCount" : 0,
	"modifiedCount" : 0,
	"upsertedId" : ObjectId("5e99f20346296441706dfb4d")
}
public class User
{
    [BsonId]
    [BsonIgnoreIfDefault] // required for replace documents 
    public ObjectId Id { get; set; }
    public Gender Gender { get; set; }
    public string FirstName {get; set; }
    public string LastName {get; set; }
    public string UserName {get; set; }
    public string Avatar {get; set; }
    public string Email {get; set; }
    public DateTime DateOfBirth {get; set; }
    public AddressCard Address {get; set; }
    public string Phone {get; set; }
    
    [BsonIgnoreIfDefault]
    public string Website {get; set; }
    public CompanyCard Company {get; set; }
    public decimal Salary { get; set; }
    public int MonthlyExpenses { get; set; }
    public List<string> FavoriteSports { get; set; }
    public string Profession { get; set; }
}

When no match found, the update result will be the following:

{
	"acknowledged" : true,
	"matchedCount" : 0, // no match found
	"modifiedCount" : 0, // so nothing modified
	"upsertedId" : ObjectId("5e99f20346296441706dfb4d")
}

FindOneAndReplaceOne

IMongoCollection<T> contains a FindOneAndReplaceOne method that behaves exactly the same as the ReplaceOne except that the returned result is of type T instead of a ReplaceOneResult, in other words it returns the updated or upserted document itself. This can be quite convenient when you want to keep working with the new document after replacing it.

IMongoCollection<T>
    .FindOneReplaceOne(FilterDefinition<T> filter, 
                T document, 
                FindOneAndReplaceOptions options)

The sample replaces the first document with a new one and gets back the entire document.

ReplaceDocuments.cs
var collection = database
  .GetCollection<User>(Constants.UsersCollection);

var firstDbUser = await collection.
            Find(Builders<User>.Filter.Empty)
            .FirstOrDefaultAsync();
            
// this is the new document - demo only
var newUser = RandomData.GenerateUsers(1).First();
newUser.Id = firstDbUser.Id;
newUser.FirstName = "Chris";
newUser.LastName = "Sakellarios";
newUser.Website = "https://github.com/chsakell";

// replace the first document in the collection
var firstUser = await collection
.FindOneAndReplaceAsync(
    Builders<User>.Filter.Eq(u => u.Id, firstDbUser.Id), 
    newUser,
    new FindOneAndReplaceOptions<User> 
                {ReturnDocument = ReturnDocument.After});
var bsonCollection = database
     .GetCollection<BsonDocument>(Constants.UsersCollection);

// this is the new document - demo only

var newUser = RandomData.GenerateUsers(1).First();
newUser.Id = firstDbUser.Id;
newUser.FirstName = "Chris";
newUser.LastName = "Sakellarios";
newUser.Website = "https://github.com/chsakell";

var bsonFirstUser = await bsonCollection.FindOneAndReplaceAsync(
        Builders<BsonDocument>.Filter.Eq("_id", firstDbUser.Id), 
        newUser.ToBsonDocument(),
        new FindOneAndReplaceOptions<BsonDocument> 
            { ReturnDocument = ReturnDocument.After });
public class User
{
    [BsonId]
    [BsonIgnoreIfDefault] // required for replace documents 
    public ObjectId Id { get; set; }
    public Gender Gender { get; set; }
    public string FirstName {get; set; }
    public string LastName {get; set; }
    public string UserName {get; set; }
    public string Avatar {get; set; }
    public string Email {get; set; }
    public DateTime DateOfBirth {get; set; }
    public AddressCard Address {get; set; }
    public string Phone {get; set; }
    
    [BsonIgnoreIfDefault]
    public string Website {get; set; }
    public CompanyCard Company {get; set; }
    public decimal Salary { get; set; }
    public int MonthlyExpenses { get; set; }
    public List<string> FavoriteSports { get; set; }
    public string Profession { get; set; }
}

FindOneAndReplaceOptions

When using the FindOneAndReplace method you have two options for the returned result:

  1. Return the updated document - you need to set ReturnDocument = ReturnDocument.After in the FindOneAndReplaceOptions

  2. Return the document before being updated - you need to set ReturnDocument = ReturnDocument.Before in the FindOneAndREplaceOptions or leave it as is since it's the default value

Since you set upsert = true a new document inserted with _id equal to the upsertedId

πŸ“‘
πŸ“
⚠️
πŸ¦‰