如何使用C#驱动程序更新MongoDB数组中的子文档

阳光灿烂的夏尔马

如何在MongoDB中修改文档的子数组中的子元素?我正在使用适用于MongoDB的最新C#驱动程序(C#驱动程序版本:2.5,服务器版本:3.2.0),并且已经尝试从SO(也有重复的问题)和其他各种来源的多个答案中获得解决方案。事实证明,大多数解决方案都是过时的。

以下是我的示例文档:

[{ 
"_id" : "69c4f77d-05ef-431d-ae17-c076c6173e04",     
"title" : "Root Page", 
"createdAt" : ISODate("2017-12-21T12:28:00.680+0000"), 
"modifiedAt" : ISODate("2017-12-26T07:18:11.165+0000"), 
"pages" : [
    {
        "_id" : "f449dc0b-3d1b-4a59-b622-6a42ce10b147", 
        "title" : "Test page 1", 
        "slug" : "test-page-1", 
        "createdAt" : ISODate("2017-12-21T12:28:00.680+0000"), 
        "modifiedAt" : ISODate("2017-12-21T12:28:00.680+0000")
    }, 
    {
        "_id" : "3d1497d7-f74c-4d88-b15c-bf2f9c736374", 
        "title" : "Test page 2", 
        "slug" : "test-page-2", 
        "createdAt" : ISODate("2017-12-25T11:27:55.006+0000"), 
        "modifiedAt" : ISODate("2017-12-25T11:27:55.006+0000")
    }, 
    {
        "_id" : "6e827e2a-5a25-4343-b646-885816bb8cc4", 
        "title" : "Test page 3", 
        "slug" : "test-page-3", 
        "createdAt" : ISODate("2017-12-25T11:31:16.516+0000"), 
        "modifiedAt" : ISODate("2017-12-25T11:31:16.516+0000")
    }]
},
...,
...
]

文档结构:根文档包含一个子文档数组,该子文档具有元数据和页面列表(数组)

内子文件-我试图更新的标题一个的子页面内对象的页面数组,但与最新的驱动程序有没有运气这么远。

我正在使用以下过滤器和更新查询:

        var filter = Builders<SubDocument>.Filter.And(Builders<SubDocument>.Filter.Eq("_id", "xxx"), Builders<SubDocument>.Filter.ElemMatch(x => x.Pages, p => p.Id == "xxx"));

        var update = Builders<SubDocument>.Update
                        .Set("pages.$.title", "changed title")
                        .Set("pages.$.slug", "changed-title")
                        .Set("pages.$.modifiedAt", DateTime.UtcNow);

        _mongoDb.Documents.UpdateOne(filter, update);

现在-此查询返回一个错误:

无效的BSON字段名称页面。$。title

我最近几个小时来的引用都说使用“ $”运算符,但它在最新的驱动程序中引发错误。

[编辑1]这是我的模型:

public class SubDocument
{
    public SubDocument()
    {
        Id = Guid.NewGuid().ToString();
        CreatedAt = DateTime.UtcNow;
        ModifiedAt = DateTime.UtcNow;
        Pages = new List<Page>();
    }

    [BsonId]
    public string Id { get; set; }        

    [BsonElement("title")]
    public string Title { get; set; }        

    [BsonElement("createdAt")]
    public DateTime CreatedAt { get; set; }

    [BsonElement("modifiedAt")]
    public DateTime ModifiedAt { get; set; }

    [BsonElement("pages")]
    public List<Page> Pages { get; set; }


}

public class Page
{
    [BsonId]
    public string Id { get; set; }

    [BsonElement("title")]
    public string Title { get; set; }

    [BsonElement("slug")]
    public string Slug { get; set; }

    [BsonElement("createdAt")]
    public DateTime CreatedAt { get; set; }

    [BsonElement("modifiedAt")]
    public DateTime ModifiedAt { get; set; }

}

任何人?提前致谢!

马切洛

您的代码实际上适用于mongod v3.4和驱动程序v2.5。

正如Evk在注释中所建议的那样,这是代码的强类型版本,可重构。

var filter = Builders<SubDocument>.Filter
    .And(
        Builders<SubDocument>.Filter.Eq(d => d.Id, "69c4f77d-05ef-431d-ae17-c076c6173e04"), 
        Builders<SubDocument>.Filter.ElemMatch(x => x.Pages, p => p.Id == "3d1497d7-f74c-4d88-b15c-bf2f9c736374"));

var update = Builders<SubDocument>.Update
                .Set(c => c.Pages[-1].Title, "changed title")
                .Set(c => c.Pages[-1].Slug, "changed slug")
                .Set(c => c.Pages[-1].ModifiedAt, DateTime.UtcNow);

subDocumentsCollection.UpdateOne(filter, update);

另一种方法可能将您的子文档实体视为一个整体(面向文档的数据库鼓励采用这种方法),因此始终要完全更新该实体,并避免进行细粒度的更新(在R-DBMS的情况下更有可能)。在这种情况下,您可能会编写如下内容。

var document = subDocumentsCollection
    .Find(d => d.Id == "69c4f77d-05ef-431d-ae17-c076c6173e04")
    .Single();

var page = document.Pages.Single(p => p.Id == "3d1497d7-f74c-4d88-b15c-bf2f9c736374");

page.Title = "changed title";
page.Slug = "changed slug";
page.ModifiedAt = DateTime.UtcNow;

subDocumentsCollection.ReplaceOne(d => d.Id == document.Id, document);

第二种方法具有以下优点和缺点。

专业人士

  • 更新发生在域层(可能通过非常合适的方法),从而允许强制执行所有域规则并防止脏数据进入数据库;因此它更加面向对象
  • 由于代码是面向领域的,因此它简单得多,并且不依赖于数据库内部。

缺点

  • 这种方法需要对数据库进行两次点击(一次用于读取,一次用于更新);
  • 如果您的实体很大,网络必须传输比严格需要更多的数据。

考虑到过早的优化是编程这里中所有邪恶(或至少是大多数邪恶)的根源,通常我会选择第二种方法,只有在对性能的要求非常严格或较低的情况下才退回到第一种方法。网络带宽。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何使用C#驱动程序更新MongoDB中数组子文档中包含的数组子文档中的字段?

如何使用C#驱动程序删除mongodb文档中的嵌套数组元素

Mongodb C# 驱动程序只返回数组中匹配的子文档

MongoDB C#驱动程序-更新嵌入式文档数组中的所有字段

如何使用mongodb C#驱动程序获取子文档的集合?

使用C#驱动程序更新MongoDB中的多个数组项

我们如何使用MongoDB Java驱动程序在MongoDB中追加/更新集合的子文档?

如何在MongoDB 2.7中使用MongoDB C#驱动程序更新通用类型

如何在 C# Mongodb 强类型驱动程序中删除嵌套文档的数组内的元素

使用MongoDB和C#新驱动程序版本(2.0)更新集合中的嵌入式文档

Mongodb C#驱动程序更新所有子数组元素

如何在不使用 Builders 的情况下使用 .net(c#) 驱动程序更新 mongo db 中的文档?

如何使用 Java 驱动程序在 MongoDB 中获取嵌入文档数组的特定值

如何在MongoDB C#驱动程序中按值的字段范围选择文档?

如何使用C#驱动程序在无类MongoDB上找到匹配的'StartsWith'文档

MongoDB使用C#驱动程序根据数组中的第N个值更新多个记录

使用C#驱动程序在mongodb中查找计算值最高的文档

使用C#驱动程序的MongoDB更新阵列

C#MongoDB驱动程序:如何将新的子文档插入现有文档

mongoDB:C#驱动程序V2如何更新嵌套集合中的项目

如何使用MongoDB C#驱动程序更新泛型类型

使用MongoDB C#驱动程序从父子层次结构中查找和更新节点

如何使用MongoDB C#驱动程序进行$ lookup?

如何使用MongoDB C#驱动程序聚合$ lookup?

Mongodb通过C#驱动程序使用多个字段匹配更新嵌入式文档

使用MongoDB和C#新驱动程序版本(2.0)更新嵌入式文档属性

从驱动程序v1迁移C#驱动程序v2中的更新文档

带有聚合管道的MongoDB C#驱动程序更新文档

MongoDB C#驱动程序2.0-更新文档