Manny
Manny

Reputation: 833

MongoDB: update only specific fields

I am trying to update a row in a (typed) MongoDB collection with the C# driver. When handling data of that particular collection of type MongoCollection<User>, I tend to avoid retrieving sensitive data from the collection (salt, password hash, etc.)

Now I am trying to update a User instance. However, I never actually retrieved sensitive data in the first place, so I guess this data would be default(byte[]) in the retrieved model instance (as far as I can tell) before I apply modifications and submit the new data to the collection.

Maybe I am overseeing something trivial in the MongoDB C# driver how I can use MongoCollection<T>.Save(T item) without updating specific properties such as User.PasswordHash or User.PasswordSalt? Should I retrieve the full record first, update "safe" properties there, and write it back? Or is there a fancy option to exclude certain fields from the update?

Thanks in advance

Upvotes: 14

Views: 40637

Answers (4)

Vitaly
Vitaly

Reputation: 2125

Had the same problem and since I wanted to have 1 generic method for all types and didn't want to create my own implementation using Reflection, I end up with the following generic solution (simplified to show all in one method):

Task<bool> Update(string Id, T item)
{
    var serializerSettings = new JsonSerializerSettings()
            {
                NullValueHandling = NullValueHandling.Ignore,
                DefaultValueHandling = DefaultValueHandling.Ignore
            };
    var bson = new BsonDocument() { { "$set", BsonDocument.Parse(JsonConvert.SerializeObject(item, serializerSettings)) } };
    await database.GetCollection<T>(collectionName).UpdateOneAsync(Builders<T>.Filter.Eq("Id", Id), bson);
}

Notes:

  • Make sure all fields that must not update are set to default value.

  • If you need to set field to default value, you need to either use DefaultValueHandling.Include, or write custom method for that update

  • When performance matters, write custom update methods using Builders<T>.Update

    P.S.: It's obviously should have been implemented by MongoDB .Net Driver, however I couldn't find it anywhere in the docs, maybe I just looked the wrong way.

Upvotes: 5

Vikash Pandey
Vikash Pandey

Reputation: 5443

Well there are many ways to updated value in mongodb.

Below is one of the simplest way I choose to update a field value in mongodb collection.

public string UpdateData()
        {               
            string data = string.Empty;
            string param= "{$set: { name:'Developerrr New' } }";
            string filter= "{ 'name' : 'Developerrr '}";
            try
            {  
               //******get connections values from web.config file*****
                var connectionString = ConfigurationManager.AppSettings["connectionString"];
                var databseName = ConfigurationManager.AppSettings["database"];
                var tableName = ConfigurationManager.AppSettings["table"];

                //******Connect to mongodb**********
                var client = new MongoClient(connectionString);
                var dataBases = client.GetDatabase(databseName);
                var dataCollection = dataBases.GetCollection<BsonDocument>(tableName);       

                //****** convert filter and updating value to BsonDocument*******
                BsonDocument filterDoc = BsonDocument.Parse(filter);
                BsonDocument document = BsonDocument.Parse(param);

                //********Update value using UpdateOne method*****
                dataCollection.UpdateOne(filterDoc, document);                   
                data = "Success";
            }
            catch (Exception err)
            {
                data = "Failed - " + err;
            }
            return data;    
        }

Hoping this will help you :)

Upvotes: 2

user6356311
user6356311

Reputation: 59

It´s possible to add more criterias in the Where-statement. Like this:

var db = ReferenceTreeDb.Database;
var packageCol = db.GetCollection<Package>("dotnetpackage");
var filter = Builders<Package>.Filter.Where(_ => _.packageName == packageItem.PackageName.ToLower() && _.isLatestVersion);
var update = Builders<Package>.Update.Set(_ => _.isLatestVersion, false);
var options = new FindOneAndUpdateOptions<Package>();
packageCol.FindOneAndUpdate(filter, update, options);

Upvotes: 6

Nuk Nuk San
Nuk Nuk San

Reputation: 560

Save(someValue) is for the case where you want the resulting record to be or become the full object (someValue) you passed in.

You can use

var query = Query.EQ("_id","123");
var sortBy = SortBy.Null;
var update = Update.Inc("LoginCount",1).Set("LastLogin",DateTime.UtcNow); // some update, you can chain a series of update commands here

MongoCollection<User>.FindAndModify(query,sortby,update); 

method.

Using FindAndModify you can specify exactly which fields in an existing record to change and leave the rest alone.

You can see an example here.

The only thing you need from the existing record would be its _id, the 2 secret fields need not be loaded or ever mapped back into your POCO object.

Upvotes: 21

Related Questions