受欢迎的博客标签

How to Update Inside a Nested Array with the official MongoDB C# driver?

Published

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://www.mattburkedev.com/updating-inside-a-nested-array-with-the-mongodb-positional-operator-in-c-number/

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();
        }
    }
}