Mongo 更新数组元素 (.NET 驱动程序 2.0)

本文关键字:驱动程序 NET 更新 数组元素 Mongo | 更新日期: 2023-09-27 18:02:56

>编辑:不是寻找JavaScript的方式来做到这一点。我正在寻找MongoDB C# 2.0驱动程序的方式来做到这一点(我知道这可能是不可能的;但我希望有人知道解决方案(。

我正在尝试更新嵌入在我的 mongodb 主文档上的数组中的项目的值。

我正在寻找一种强类型的方式来做到这一点。我正在使用Mongodb c# 2.0驱动程序

我可以通过弹出元素、更新值然后重新插入来做到这一点。这感觉不对;因为我正在覆盖在此期间可能写的内容。

这是我到目前为止尝试过但没有运气的方法:

private readonly IMongoCollection<TempAgenda> _collection;
void Main()
{
    var collectionName = "Agenda";
    var client = new MongoClient("mongodb://localhost:27017");
    var db = client.GetDatabase("Test");
    _collection = db.GetCollection<TempAgenda>(collectionName);
    UpdateItemTitle(1, 1, "hello");
}
public void UpdateItemTitle(string agendaId, string itemId, string title){
    var filter = Builders<TempAgenda>.Filter.Eq(x => x.AgendaId, agendaId);
    var update = Builders<TempAgenda>.Update.Set(x => x.Items.Single(p => p.Id.Equals(itemId)).Title, title);
    var result = _collection.UpdateOneAsync(filter, update).Result;
}

Mongo 更新数组元素 (.NET 驱动程序 2.0)

我花了一段时间才弄清楚这一点,因为它似乎没有在任何官方文档(或其他任何地方(中提及。但是,我确实在他们的问题跟踪器上找到了这个,它解释了如何将位置运算符$与 C# 2.0 驱动程序一起使用。

这应该做你想要的:

public void UpdateItemTitle(string agendaId, string itemId, string title){
    var filter = Builders<TempAgenda>.Filter.Where(x => x.AgendaId == agendaId && x.Items.Any(i => i.Id == itemId));
    var update = Builders<TempAgenda>.Update.Set(x => x.Items[-1].Title, title);
    var result = _collection.UpdateOneAsync(filter, update).Result;
}

请注意,Item.Single() 子句已更改为 Item.Any() 并移至筛选器定义。

[-1].ElementAt(-1)显然是经过特殊处理的(实际上是 0

以上内容将转换为此查询:

db.Agenda.update({ AgendaId: 1, Items.Id: 1 }, { $set: { Items.$.Title: "hello" } })

谢谢,这很有帮助。 不过我有一个补充,我已经将上述内容用于数组,推送到嵌套数组并从中拉取。 我发现的问题是,如果我有一个 int 数组(所以不是一个对象,只是一个简单的 int 数组(,那么 PullFilter 实际上不起作用 - "无法确定序列化信息"这很奇怪,因为它只是一个整数数组。 我最终做的是使其成为只有一个 int 参数的对象数组,然后一切都开始工作了。 可能是错误,也可能是我缺乏理解。无论如何,由于我一直在努力查找有关使用 C# 2.0 驱动程序拉取和推送到嵌套对象数组的信息,我想我应该在这里发布我的发现,因为它们使用上述语法。

var filter = Builders<MessageDto>.Filter.Where(x => x._id == entity.ParentID && x.NestedArray.Any(i => i._id == entity._id));
var update = Builders<MessageDto>.Update.PullFilter(x => x.NestedArray.ElementAt(-1).User, Builders<User>.Filter.Eq(f => f.UserID, userID));
Collection<MessageDto>(currentUser).UpdateOneAsync(filter, update);

还有:

var filter = Builders<MessageDto>.Filter.Where(x => x._id == entity.ParentID && x.NestedArray.Any(i => i._id == entity._id));
var update = Builders<MessageDto>.Update.Push(x => x.NestedArray.ElementAt(-1).Users, new User { UserID = userID });
Collection<MessageDto>(currentUser).UpdateOneAsync(filter, update);

在较新的驱动程序中,可能不再支持ElementAt(-1)。 我有 (-1( 的代码在转到 .NET6MongoDB Driver 2.19.0时停止工作

他们引入了ExtensionMethods:

x.A.FirstMatchingElement() => "A.$"
x.A.AllElements() => "A.$[]"
x.A.AllMatchingElements("identifier") => "A.$[identifier]"

这是上述答案的组合工作解决方案,其中.NET 7MongoDB.Driver 2.20.0

使用FirstMatchingElement()AllElements()代替[-1]

  • AgnendaId是父母的
  • Items是嵌套数组
<小时 />

更新第一个匹配元素

public void UpdateItemTitle(string agendaId, string itemId, string title)
{
    var filter = Builders<TempAgenda>.Filter.Where(x => x.AgendaId == agendaId && x.Items.Any(i => i.Id == itemId));
    var update = Builders<TempAgenda>.Update.Set(x => x.Items.FirstMatchingElement().Title, title);
    _collection.UpdateOneAsync(filter, update);
}

更新所有元素

public void UpdateItemTitle(string agendaId, string itemId, string title)
{
    var filter = Builders<TempAgenda>.Filter.Where(x => x.AgendaId == agendaId && x.Items.Any(i => i.Id == itemId));
    var update = Builders<TempAgenda>.Update.Set(x => x.Items.AllElements().Title, title);
    _collection.UpdateOneAsync(filter, update);
}

更新文档或子数组的正确方法如下:

var filter = Builders<Declaracion>.Filter.Where(x => x.Id == di && x.RemuneracionMensualActual.RemuneracionActIndustrial.Any(s => s.Id == oid));
        var update = Builders<Declaracion>.Update.Set(x => x.RemuneracionMensualActual.RemuneracionActIndustrial.ElementAt(-1).Ingreso, datos.ActividadIndustrial.Ingreso)
            .Set(x => x.RemuneracionMensualActual.RemuneracionActIndustrial.ElementAt(-1).RazonSocial, datos.ActividadIndustrial.RazonSocial)
            .Set(x => x.RemuneracionMensualActual.RemuneracionActIndustrial.ElementAt(-1).TipoNegocio, datos.ActividadIndustrial.TipoNegocio);