Replace
Last updated
Last updated
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.
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);
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.
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);
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.
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
});
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.
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});
When using the FindOneAndReplace
method you have two options for the returned result:
Return the updated document - you need to set ReturnDocument = ReturnDocument.After
in the FindOneAndReplaceOptions
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