如何使用C#更新深度嵌套mongodb结构中的数组元素(尝试使用位置运算符更新文档))

如何使用C#更新深度嵌套mongodb结构中的数组元素(尝试使用位置运算符更新文档)),c#,mongodb,C#,Mongodb,我正在尝试访问一个深度嵌套的mongodb结构,并希望使用c#更新和读取该结构。我想更新UUT数组中的UUT对象,以及UUT历史数组 我正在尝试更新UUTId:TS220,clockingcycles:2000的值 我知道有一个选项可以覆盖整个文档,但我不知道如何访问UUTId对象并为clockingcycles插入一个值 请使用c#MongoDB.Driver进行回答 提前谢谢 MongoClient mongoClient = new MongoClient("mongodb://serve

我正在尝试访问一个深度嵌套的mongodb结构,并希望使用c#更新和读取该结构。我想更新UUT数组中的UUT对象,以及UUT历史数组

我正在尝试更新UUTId:TS220,clockingcycles:2000的值

我知道有一个选项可以覆盖整个文档,但我不知道如何访问UUTId对象并为clockingcycles插入一个值

请使用c#MongoDB.Driver进行回答 提前谢谢

MongoClient mongoClient = new MongoClient("mongodb://server.net:27017");
IMongoDatabase db = mongoClient.GetDatabase("enduranceTest");
IMongoCollection<ServerTreeVm> collectionEndurance = db.GetCollection<ServerTreeVm>("EnduranceTests");


var filterVM = Builders<ServerTreeVm>.Filter;
            var enduranceTestFound = filterVM.And(
                Builders<ServerTreeVm>.Filter.Where(x => x.Countries.Any(y =>
                    y.Cities.Any(z => z.EnduranceTests.Any(a => a.EnduranceTestName == "Endurance 1")))),
                Builders<ServerTreeVm>.Filter.Where(x => x.Countries.Any(y =>
                    y.Cities.Any(z => z.EnduranceTests.Any(a => a.EnduranceInfo.Any(b=>b.Title== "Taktverteiler_1"))))),
                Builders<ServerTreeVm>.Filter.Where(x => x.Countries.Any(y =>
                    y.Cities.Any(z => z.EnduranceTests.Any(a => a.EnduranceInfo.Any(b => b.Channels.Any(c=>c.Uuts.Any(d=>d.UutId == "TS220"))))))));

            var enduranceTest = collectionEndurance.Find(enduranceTestFound).SingleOrDefault();

            //update with positional operator
            var update = Builders<ServerTreeVm>.Update;

            UUT uutObj = new UUT
            {
              Status = "Running",
              UutId = "TS220",
              ClockingCycles = 2000,
              Offset = 100,
              StartCycles = 0,
              Timestamp = DateTime.Now,
              UUTHistory = null
            };

            var enduranceUpdate = update.Set("Countries.$.Cities.$.EnduranceTest.$.ClockDistributor.$.Channels.$.UUTs.$", uutObj);
            collectionEndurance.UpdateOne(enduranceTestFound, enduranceUpdate);

[BsonIgnoreExtraElements]
公共类ServerTreeVm
{
[b单一元素(“国家”)]
公共列表国家{get;set;}
公共字符串ActiveEnduranceTest{get;set;}
公共字符串ActiveDistributor{get;set;}
}
[BsonIgnoreExtraElements]
公营国家
{
[b单一元素(“城市”)]
公共列表城市{get;set;}
[b单一元素(“国家名称”)]
公共字符串CountryName{get;set;}
}
[BsonIgnoreExtraElements]
公营城市
{
[B单一元素(“持久性测试”)]
公共列表EnduranceTests{get;set;}
[b单一元素(“城市名称”)]
公共字符串CityName{get;set;}
}
[BsonIgnoreExtraElements]
公共级耐力
{
[BsonElement(“时钟分配器”)]
公共列表EnduranceInfo{get;set;}
[B单一元素(“EnduranceTestName”)]
公共字符串EnduranceTestName{get;set;}
}
[BsonIgnoreExtraElements]
公共类受测试单元
{
[BsonElement(“UUTId”)]
公共字符串UutId{get;set;}
[b单一元素(“时钟周期”)]
公共双时钟周期{get;set;}
[b单一元素(“状态”)]
公共字符串状态{get;set;}
[b单一元素(“开始循环”)]
公共双开始循环{get;set;}
[b单一要素(“抵销”)]
公共双偏移量{get;set;}
[b单一元素(“时间戳”)]
公共日期时间时间戳{get;set;}
[b单一元素(“本文档”)]
公共列表UUTHistory{get;set;}
}
[BsonIgnoreExtraElements]
公共类图书馆
{
[b单一元素(“时钟周期”)]
公共双时钟周期{get;set;}
[b单一元素(“状态”)]
公共字符串状态{get;set;}
[b单一元素(“开始循环”)]
公共双开始循环{get;set;}
[b单一要素(“抵销”)]
公共双偏移量{get;set;}
[b单一元素(“时间戳”)]
公共日期时间时间戳{get;set;}
}
[BsonIgnoreExtraElements]
公共类通道对象
{
[BsonElement(“UUT”)]
公共列表UUT{get;set;}
[b单一元素(“信道周期”)]
公共双通道循环{get;set;}
[b单一元素(“节点名称”)]
公共字符串节点名{get;set;}
}
[BsonIgnoreExtraElements]
公共类持久性信息
{
[B单一元素(“IP”)]
公共字符串Ip{get;set;}
[b单一元素(“标题”)]
公共字符串标题{get;set;}
[b单一元素(“链接”)]
公共字符串链接{get;set;}
[BsonElement(“PropertyNames”)]
公共列表属性名称{get;set;}
[b单一元素(“节点”)]
公共列表节点{get;set;}
[b单一元素(“通道”)]
公共列表频道{get;set;}
[b单一元素(“连接类型”)]
公共字符串连接类型{get;set;}
[BsonElement(“StartStopNodes”)]
公共列表StartStopNodeNames{get;set;}
}

这并不能真正解决您真正的问题,即如何使用C#mongo驱动程序,但这可能会有所帮助。我把它放在这里而不是上面的注释,因为我想说明一些代码概念,并需要格式化选项

请允许我详细说明以下几点

您的代码具有以下lambda查询条件

(a => a.EnduranceInfo.Any(b=>b.Title== "Taktverteiler_1"))
。。。但是您的示例文档没有此字段。这将导致找不到要更新的文档。类似地,由于
EnduranceInfo
不存在以下lambda查询表达式

(a => a.EnduranceInfo.Any(b => b.Channels.Any(c=>c.Uuts.Any(d=>d.UutId == "TS220"))))
。。。也将无法找到匹配的文档

我经常将MongoDB与RDBMS系统进行比较。在Mongo中构造标准的“find()”操作时,第一个条件是查询。这是一个可怕的名称,因为它不是查询,而是“查找匹配的文档”子句。如果创建MongoDB find()命令并仅提供第一个参数(假设找到匹配项),则将收到整个文档。这意味着第一个参数相当于传统RDBMS系统中的“WHERE”子句。尚未建立“SELECT”子句

所以,你的问题更有针对性。您不仅希望找到要更新的特定文档,还希望更新找到的文档的特定部分。查询的“查找”部分查找文档。然后必须定义查询的其他部分,以确定要更新文档的哪个部分。您的代码试图通过两行代码以文档的特定部分为目标

var enduranceUpdate = update.Set("Countries.$.Cities.$.EnduranceTest.$.ClockDistributor.$.Channels.$.UUTs.$", uutObj);
collectionEndurance.UpdateOne(enduranceTestFound, enduranceUpdate);
我认为您的想法是正确的,但是按照前面的讨论,find参数
enduranceTestFound
在语法上不会有任何已找到的文档。选项
enduranceUpdate
格式不正确。使用“$”表示要更新数组元素的第一次出现次数。请参阅位于的“$”上的MongoDB文档。你会看到他们特别声明

位置$operator充当第一个元素的占位符 与查询文档匹配,并且数组字段必须显示为 查询文档的一部分

为了理解我的代码需要做什么,我通常会首先使用最基本的代码识别查询
(a => a.EnduranceInfo.Any(b => b.Channels.Any(c=>c.Uuts.Any(d=>d.UutId == "TS220"))))
var enduranceUpdate = update.Set("Countries.$.Cities.$.EnduranceTest.$.ClockDistributor.$.Channels.$.UUTs.$", uutObj);
collectionEndurance.UpdateOne(enduranceTestFound, enduranceUpdate);
db.enduranceTest.update(
    { "Countries.Cities.EnduranceTests.EnduranceTestName": "endurance1" }, 
    { $set: {
        "Countries.$[].Cities.$[].EnduranceTests.$[].ClockDistributor.$[].Channels.$[].UUTs.$[myplaceholder].ClockingCycles" : 2000,
        "Countries.$[].Cities.$[].EnduranceTests.$[].ClockDistributor.$[].Channels.$[].UUTs.$[myplaceholder].Status" : "Running",
        "Countries.$[].Cities.$[].EnduranceTests.$[].ClockDistributor.$[].Channels.$[].UUTs.$[myplaceholder].StartCycles" : 0,
        "Countries.$[].Cities.$[].EnduranceTests.$[].ClockDistributor.$[].Channels.$[].UUTs.$[myplaceholder].Offset" : 2000,
        "Countries.$[].Cities.$[].EnduranceTests.$[].ClockDistributor.$[].Channels.$[].UUTs.$[myplaceholder].Timestamp" : new Date(),
        "Countries.$[].Cities.$[].EnduranceTests.$[].ClockDistributor.$[].Channels.$[].UUTs.$[myplaceholder].UUTHistory" : null,
      } 
    },
    {
      arrayFilters: [
        { "myplaceholder.UUTId" : "TS220" }
      ]
    }
)
` UUT uutObj = new UUT
                {
                  Status = "laüft",
                  UutId = "TS220",
                  ClockingCycles = 2000,
                  Offset = 100,
                  StartCycles = 0,
                  Timestamp = DateTime.Now,
                  UUTHistory = null
                };

    var enduranceUpdate = update.Set("Countries.0.Cities.0.EnduranceTest.0.ClockDistributor.0.Channels.0.UUTs.$", uutObj);`