【问题标题】:MongoDB: update only specific fieldsMongoDB:仅更新特定字段
【发布时间】:2013-02-13 12:15:42
【问题描述】:

我正在尝试使用 C# 驱动程序更新(类型化的)MongoDB 集合中的一行。在处理 MongoCollection<User> 类型的特定集合的数据时,我倾向于避免从集合中检索敏感数据(盐、密码哈希等)

现在我正在尝试更新 User 实例。但是,我从来没有真正检索过敏感数据,所以我猜在我应用修改并将新数据提交到集合之前,检索到的模型实例中的数据将是default(byte[])(据我所知)。

也许我正在监督 MongoDB C# 驱动程序中的一些琐碎事情,如何在不更新特定属性(例如 User.PasswordHashUser.PasswordSalt)的情况下使用 MongoCollection<T>.Save(T item)?我应该先检索完整记录,更新那里的“安全”属性,然后再写回去吗?或者是否有从更新中排除某些字段的奇特选项?

提前致谢

【问题讨论】:

    标签: c# mongodb mongodb-.net-driver


    【解决方案1】:

    Save(someValue) 适用于您希望结果记录成为或成为您传入的完整对象 (someValue) 的情况。

    你可以使用

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

    方法。

    使用 FindAndModify,您可以准确指定现有记录中的哪些字段要更改,而无需考虑其余部分。

    你可以看一个例子here

    现有记录中唯一需要的就是它的 _id,这两个秘密字段不需要加载或映射回您的 POCO 对象。

    【讨论】:

    • 感谢您指出这一点。但是我的潜在问题仍然存在:我希望使用T 实例的值更新我输入的MongoCollection&lt;T&gt; 中的所有属性,除了一组特定的已知字段。类似于Update&lt;T&gt;.EverythingFrom(someObject).Except(x =&gt; x.ExceptThis).Except(x =&gt; x.ExceptThat)
    • 这是您需要编写的自定义作业 (EverythingFrom..)。在客户端做起来并不难,通过遍历 BsonMemberMap 并获取所有映射的成员,然后如果您知道该值已更改,则只需从每个成员构建一个 Update.Set()。不能保证连贯,因为自从您将记录读入内存后数据库可能已经发生变化。
    【解决方案2】:

    可以在 Where 语句中添加更多条件。像这样:

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

    【讨论】:

      【解决方案3】:

      遇到了同样的问题,因为我想为所有类型使用 1 个通用方法并且不想使用反射创建自己的实现,所以我最终得到了以下通用解决方案(简化为在一个方法中显示所有内容):

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

      注意事项:

      • 确保所有不能更新的字段都设置为默认值。

      • 如果您需要将字段设置为默认值,您需要使用 DefaultValueHandling.Include,或者为该更新编写自定义方法

      • 当性能很重要时,使用Builders&lt;T&gt;.Update编写自定义更新方法

        P.S.:它显然应该由 MongoDB .Net Driver 实现,但是我在文档中的任何地方都找不到它,也许我只是看错了方式。

      【讨论】:

      • 帮了我很多,但最好用item.ToBsonDocument()而不是BsonDocument.Parse(JsonConvert.SerializeObject(item, serializerSettings))
      • 我记得我不能让 ToBsonDocument 排除默认值,这就是我使用 JsonConvert 的原因。也许它在新版本中效果更好,或者我忽略了设置
      • 我在模型属性上使用了装饰器[BsonIgnoreIfDefault],所以可能这就是它对我有用的原因
      【解决方案4】:

      嗯,有很多方法可以更新mongodb 中的值。

      以下是我选择更新 mongodb 集合中字段值的最简单方法之一。

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

      希望对您有所帮助:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-03
        • 1970-01-01
        • 2023-04-09
        相关资源
        最近更新 更多