Sometimes you have a document in MongoDB with a property that is an array of nested objects. You’d like to update one of those objects.
a simple document representing a class with students:
Class.json
{
"_id" : ObjectId("583ee54339eddb19c03f2bf5"),
"Name" : "Introduction to Databases",
"Code" : "CS321",
"Students" : [
{
"Name" : "Alice",
"Grade" : 92
},
{
"Name" : "Bob",
"Grade" : 87
},
{
"Name" : "Charlie",
"Grade" : 76
}
]
}
I’d like to update Bob’s grade to a 93 since he passed his last exam.
One simple way to do it is to load the whole Class document into memory, update the grade in C#, and then put the document back into the database.
1.Update Whole Document
var client = new MongoClient("mongodb://localhost:27017")
var db = client.GetDatabase("school");
var classes = db.GetCollection<Class>("classes");
// Bring the whole Class document into memory
var classToUpdate = classes.Find(c => c.Code == "CS321").First();
// Find bob in the Students array
var bob = classToUpdate.Students.First(s => s.Name == "Bob");
// Update Bob's grade
bob.Grade = 93;
// Save the entire document back to the database
classes.ReplaceOne(c => c.Id == classToUpdate.Id, classToUpdate);
2.Update element
db.classes.findAndModify({
query: { Code: "CS321", Students: { $elemMatch: { Name: "Bob" } } },
update: { $set: { "Students.$.Grade": NumberInt(89) } }
})
var client = new MongoClient("mongodb://localhost:27017")
var db = client.GetDatabase("school");
var classes = db.GetCollection<Class>("classes");
classes.FindOneAndUpdate(
c => c.Code == "CS321" && c.Students.Any(s => s.Name == "Bob"), // find this match
Builders<Class>.Update.Set(c => c.Students[-1].Grade, 72)); // -1 means update first matching array element
or
classes.FindOneAndUpdate(
c => c.Code == "CS321" && c.Students.Any(s => s.Name == "Bob"),
Builders<Class>.Update.Set(c => c.Students.FirstMatching().Grade, 72));
sample2:
MongoDB document model:
{
"title": "Presidential elections",
"author": "Joe Black",
"description": "Very important poll",
"votes": [
{
"name": "Margaret",
"yes": true,
"guid": "6c909a36-8a3d-4b42-926f-85d7c16081b6"
},
{
"name": "Michael",
"yes": false,
"guid": "3e226bb0-d39b-4d08-bea2-a707606db7de"
}
]
}
Poll.cs
public class Poll : MongoDocument
{
public string Author { get; set; }
public string Description { get; set; }
public PollType PollType { get; set; }
public string Title { get; set; }
public List<Vote> Votes { get; set; }
}
Vote.cs
public class Vote
{
public string Name { get; set; }
public bool Yes { get; set; }
public DateTime LastModified { get; private set; }
public Guid Guid { get; private set; }
}
update on single vote, using it’s GUID
public async Task<bool> UpdateVote(string id, DTO.Vote vote)
{
var poll = GetPoll(id);
var update = Builders<Poll>.Update.Combine(
Builders<Poll>.Update.Set(x => x.Votes[-1].Name, vote.Name),
Builders<Poll>.Update.Set(x => x.Votes[-1].Yes, vote.Yes));
var filter = Builders<Poll>.Filter.And(
Builders<Poll>.Filter.Eq(x => x.Id, ObjectId.Parse(id)),
Builders<Poll>.Filter.ElemMatch(x => x.Votes, x => x.Guid == vote.Guid));
var result = await _context.Polls.UpdateOneAsync(filter, update);
return result.IsAcknowledged
&& result.ModifiedCount > 0;
}
https://jacekstyrylski.github.io/2018/02/01/MongoDB-Update-array-element-net/
sample3:
How to update multiple Specific Embedded documents within the same arraywith the official MongoDB C# driver?
using MongoDB.Entities;
namespace StackOverflow
{
public class Program
{
public class Parent : Entity
{
public ChildA[] ChildrenA { get; set; }
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public ChildB[] ChildrenB { get; set; }
}
public class ChildA : Entity
{
public string Property { get; set; }
public string Property2 { get; set; }
}
public class ChildB
{
public string Property { get; set; }
public string Property2 { get; set; }
}
static void Main(string[] args)
{
new DB("test");
var childA = new ChildA { Property = "update-me", Property2 = "leave-me-alone" };
var childB = new ChildA { Property = "leave-alone", Property2 = "update-me" };
childA.Save(); childB.Save();
var parent = new Parent
{
ChildrenA = new[] { childA, childB },
PropertyA = "update-me",
PropertyB = "leave-me-alone",
ChildrenB = new[] {
new ChildB{ Property = "update-me", Property2 = "leave-me-alone"},
new ChildB{ Property = "leave-alone", Property2 = "update-me"}
}
};
parent.Save();
DB.Update<Parent>()
.Match(
f => f.Eq(p => p.ID, parent.ID) &
f.ElemMatch(
x => x.ChildrenA,
x => x.ID == childA.ID))
.Modify(x => x.ChildrenA[-1].Property, "UPDATED")
.Modify(x => x.PropertyA, "UPDATED")
.Modify(x => x.ChildrenB[0].Property, "UPDATED")
.Modify(x => x.ChildrenB[1].Property2, "UPDATED")
.Execute();
}
}
}