使用MongoDB 3.4.6中的C#驱动程序2.4.4更新两次嵌套文档

时间:2017-08-01 08:05:28

标签: c# mongodb

我有一个类似于以下文档的文档,用于存储许可证。删除不必要的字段。

{
  "_id" : "1",
  "company_name" : "stackOverflow",
  "license_holders" : [
    {
      "UID" : "AAA-BBB-CCC-DDD",
      "software_version" : "1.2.3",
      "licenses" : [
        {
          "creation_date" : "03.03.17",
          "is_valid" : true,
          "license_id" : "l1"
        },
        {
          "creation_date" : "03.03.16",
          "is_valid" : false,
          "license_id" : "l2"
        }
      ]
    },
    {
      "UID" : "111-222-333-444",
      "software_version" : "1.2.3",
      "licenses" : [
        {
          "creation_date" : "05.05.17",
          "is_valid" : true,
          "license_id" : "l3"
        },
        {
          "creation_date" : "05.05.16",
          "is_valid" : false,
          "license_id" : "l4"
        }
      ]
    }
  ]
}

我可以通过此查询更新具有给定UID的软件版本:

    public async Task<Customer> UpdateLicenseHolderSoftwareVersion(string uid, string softwareVersion) {
        var update = Builders<Customer>.Update.Set(c => c.LicenseHolders[-1].CurrentSoftwareVersion, softwareVersion);
        Customer customer = await DMSLicenseCollection.FindOneAndUpdateAsync(c => c.LicenseHolders.Any(h => h.UID == uid), update);
        return customer;
    }

我无法找到更新许可证"is_valid"字段的方法。我正在尝试使用UIDLicenseId字段选择正确的许可。我尝试了很多东西,但没有成功。嵌入这么多文件是不好的做法?或者我错过了更新和检索数组内部的几个层嵌套文档的方法。感谢...

1 个答案:

答案 0 :(得分:0)

我有一些建议可以让你的生活更轻松。

  • 我发现不将嵌套文档存储为列表但是字典很有用。这样,您可以轻松找到要更新的子文档。例如,UID和license_id可以是字典中的键,也可以是其余字段的值。
  • 我不是在db中识别非主键的东西的忠实粉丝。在这里,您可以根据UID和license_id更新子文档。我认为这是不好的做法,建议你改变它。
  • 对于在其中包含大量嵌套文档的大型文档,您需要适当调整其深度。更多嵌套文档意味着查询执行速度变慢。我建议您对应用程序进行基准测试,并检查您是否对速度感到满意。

解决当前问题:

 public async Task ToggleLicesneIsValid(string UID, int licenseId)
    {
        var filter = Builders<Customer>.Filter.ElemMatch(x => x.licence_holders, i => i.UID == UID);
        var customer = DMSLicenseCollection.Find(filter).FirstOrDefault();
        var item = customer.licence_holders.FirstOrDefault(x => x.UID == UID).licenses.FirstOrDefault(y => y.license_id == licenseId);

        item.is_valid = !item.is_valid;

        await DMSLicenseCollection.ReplaceOneAsync(o => o.mongoId == customer.mongoId, customer);
    }

此方法在“is_valid”上切换true / false但我建议你有两个单独的方法(一个用于设置为true,另一个用于将其设置为false)。这样代码更具可读性,您可以避免潜在的错误。

PS我在我的测试中将id命名为mongoId,但根据自己的喜好进行了更改。

干杯!