【问题标题】:Mongo update array element (.NET driver 2.0)Mongo 更新数组元素(.NET 驱动程序 2.0)
【发布时间】:2015-07-16 12:05:44
【问题描述】:

编辑: 不寻找这样做的javascript方式。我正在寻找执行此操作的 MongoDB C# 2.0 驱动程序方式(我知道这可能是不可能的;但我希望有人知道解决方案)。

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

我正在寻找一种强类型的方法来做到这一点。我正在使用Mongodb c# 2.0 driver

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

这是我迄今为止尝试过但没有运气的方法:

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

【问题讨论】:

  • @BlakesSeven 这不是 c# 问题吗?
  • 还是一样的原理。匹配查询部分中的数组元素并在更新部分中使用位置$ 运算符。我不是随便从袋子里拿出来的。
  • @BlakesSeven 我可以阅读 mongo 文档并使用纯 javascript 进行操作,但是,正如我在问题中所述,我正在寻找一种强类型的方法来执行此操作,并且据我所知嵌入我的 C# 代码中的 javascript 字符串不是强类型的。
  • still 是 C# 的位置运算符。它不是“javascript 字符串”,而是“点表示法”,适用于所有语言。

标签: c# .net mongodb


【解决方案1】:

我花了一段时间才弄清楚这一点,因为任何官方文档(或其他任何地方)似乎都没有提到它。不过,我确实在他们的问题跟踪器上找到了this,它解释了如何将位置运算符$ 与 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) 显然被特殊处理(实际上所有 $ 替换。

上面将被翻译成这个查询:

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

【讨论】:

  • 很抱歉接受您的回答这么慢。效果很好。不幸的是,它们不支持多个操作选择器:jira.mongodb.org/browse/SERVER-831 对我来说似乎很奇怪,因为这可以用来更好地隔离需要完成的更新。
  • 感谢 Søren。我必须说我不喜欢他们选择的语法,因为这意味着你不能使用 IEnumerable 或 ICollection 并迫使你使用更麻烦的 IList 或简单的数组
  • @Buvy 你应该也可以使用 LINQ 扩展方法ElementAt(-1)
  • @SørenKruse 你确实是正确的,而我刚刚验证的语法就像一个魅力。与数组索引器相比,它有点麻烦,但至少我不必让我所有的域类都使用 IList,这正是我所追求的。
  • 我尝试了这个解决方案,代码实际上编译没有任何错误,但是当我查询文档时在运行时发生了什么,该数组中的 [-1] 开始反向索引搜索而不是使用位置运算符.所以 -1 结果是数组的最后一个元素,-2 是倒数第二个。这不是我们想要的,索引应该是动态的,通过位置操作符。
【解决方案2】:

谢谢,这很有帮助。不过,我还有一个补充,我已将上述内容用于数组,推送到嵌套数组并从中拉出。我发现的问题是,如果我有一个 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);

【讨论】:

  • 你说的是一个int数组,但这个例子仍然是一个存储复杂结构的数组。显示从 int 数组中删除一个元素的示例。
【解决方案3】:

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

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

【讨论】:

  • 我认为您之所以被否决是因为有人对翻译感到不安,“正确的方式……”读作“这是一种真正的方式”,有人被冒犯了,甚至没有有礼貌发表评论。我会说您的答案确实重复了上面给出的 2 个答案,它们使用 [-1].ElementAt(-1)
猜你喜欢
  • 1970-01-01
  • 2016-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-05
  • 2023-03-21
  • 2014-05-11
  • 1970-01-01
相关资源
最近更新 更多