Search code examples
c#mongodbmongodb-.net-driver

Class is stored in MongoDB (C#), contains internal arrays. Need to update a single element in the nested array, what is the better way to do that?


.NET Core project. I have a Tenant class containing several nested collection (Locations, Employees, etc), stored in the MongoDB. I'm using the MongoDB C# driver. The Tenant is stored in the TenantCollection in the MongoDB.

Task: for example, I need to update an Employee, which is stored in the Tenant.Employees list (nested array attached to the Tenant).

BTW - the next my question will be about "how to insert the element into the nested array", so please take it into consideration as I will have to use the same mechanism later for data inserting...

Question is - what is better:

  1. Just to take the whole Tenant from the DB (containing ALL nested lists/arrays - it could be a lot of data here), update the single element in the Employees list, and put it back to the DB, by using _mongoDbCollection.ReplaceOneAsync(x => x.Id = tenant.Id, tenant)
  2. Use some MongoDB features and update the particular element in the nested collection?

Pros for point #1 - simplicity, cons - possible big amount of data - as I have to work with the class + several internal arrays (Locations, Employees, Departments, etc, but is it really important?). Possible(!!) pros for point #2 - speed... As here we update just an element of the nested array. Cons - can't figure out how to do that as I have no experience with MongoDB...

What is better - what do you think about it? And if you do prefer point #2 - how to do that?

Thanks a lot in advance!


Solution

  • Here is a method I've created:

            public async Task UpdateNestedElementAsync<TField>(Expression<Func<T, bool>> filter, Expression<Func<TField, bool>> itemFilter, Expression<Func<T, IEnumerable<TField>>> field, IEnumerable<TField> val)
        {
            // step 1 (could be skipped if we want just to add the element - pass itemFilter=NULL) - remove the element from the Collection, but it wasn't tested
            if (itemFilter != null)
            {
                await _collection.FindOneAndUpdateAsync(filter, Builders<T>.Update.PullFilter(field, itemFilter));
            }
            // step 2 - add new or updated element to the Collection (push it there)
            await _collection.FindOneAndUpdateAsync(filter, Builders<T>.Update.PushEach(field, val));
        }
    

    Where T is the root class and TField is the nested collection.