如何同时上载记录和数组元素? [英] How can I upsert a record and array element at the same time?

查看:112
本文介绍了如何同时上载记录和数组元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这应该被理解为双重upsert操作,先对文档然后对数组元素进行ups插入.

That is meant to be read as a dual upsert operation, upsert the document then the array element.

因此MongoDB对我来说是一个非规范化存储(我们是事件源),而我要处理的事情之一就是它的并发特性.问题是这样的:

So MongoDB is a denormalized store for me (we're event sourced) and one of the things I'm trying to deal with is the concurrent nature of that. The problem is this:

  • 事件可能会出现混乱,因此对数据库的每次更新都需要更新.
  • 我不仅需要向上插入父文档,还需要能够插入该文档的array属性中的元素.

例如:

  • 如果文档不存在,请创建它.此流中的所有事件都具有文档的ID,但取决于事件,仅一部分信息.
  • 如果该文档确实存在,请对其进行更新.这是简单的部分. update命令只是写为UpdateOneAsync和upsert.
  • 如果该事件实际上是要更新列表,则该列表元素需要重新插入.因此,如果该文档不存在,则需要创建该文档,然后将对列表项进行升序处理(导致插入);如果文档确实存在,那么我们需要找到该元素并将其更新为upsert,因此,如果该元素存在,则将其更新,否则将其插入.

如果可能的话,让它作为单个原子操作执行将是理想的选择,但是如果它只能分多个步骤完成,那就也是如此.由于2.x驱动程序发生了很大的变化,因此网上出现了很多混合示例.不确定我在UpdateOneAsync之外寻找什么.当前使用的是2.4.x.解释示例将不胜感激. TIA

If at all possible, having it execute as a single atomic operation would be ideal, but if it can only be done in multiple steps, then so be it. I'm getting a number of mixed examples on the net due to the large change in the 2.x driver. Not sure what I'm looking for beyond the UpdateOneAsync. Currently using 2.4.x. Explained examples would be appreciated. TIA

注意: 重申这是关于MongoDB C#驱动程序2.4.x的问题

Note: Reiterating that this is a question regarding the MongoDB C# driver 2.4.x

推荐答案

进行了一些修补,但我明白了.

Took some tinkering, but I got it.

var notificationData = new NotificationData
{
    ReferenceId = e.ReferenceId,
    NotificationId = e.NotificationId,
    DeliveredDateUtc = e.SentDate.DateTime
};

var matchDocument = Builders<SurveyData>.Filter.Eq(s => s.SurveyId, e.EntityId);

// first upsert the document to make sure that you have a collection to write to
var surveyUpsert = new UpdateOneModel<SurveyData>(
    matchDocument,
    Builders<SurveyData>.Update
        .SetOnInsert(f => f.SurveyId, e.EntityId)
        .SetOnInsert(f => f.Notifications, new List<NotificationData>())){ IsUpsert = true};

// then push a new element if none of the existing elements match
var noMatchReferenceId = Builders<SurveyData>.Filter
    .Not(Builders<SurveyData>.Filter.ElemMatch(s => s.Notifications, n => n.ReferenceId.Equals(e.ReferenceId)));

var insertNewNotification = new UpdateOneModel<SurveyData>(
    matchDocument & noMatchReferenceId,
    Builders<SurveyData>.Update
        .Push(s => s.Notifications, notificationData));

// then update the element that does match the reference ID (if any)
var matchReferenceId = Builders<SurveyData>.Filter
    .ElemMatch(s => s.Notifications, Builders<NotificationData>.Filter.Eq(n => n.ReferenceId, notificationData.ReferenceId));
var updateExistingNotification = new UpdateOneModel<SurveyData>(
    matchDocument & matchReferenceId,
    Builders<SurveyData>.Update 
        // apparently the mongo C# driver will convert any negative index into an index symbol ('$')
        .Set(s => s.Notifications[-1].NotificationId, e.NotificationId)
        .Set(s => s.Notifications[-1].DeliveredDateUtc, notificationData.DeliveredDateUtc));

// execute these as a batch and in order
var result = await _surveyRepository.DatabaseCollection
    .BulkWriteAsync(
        new []{ surveyUpsert, insertNewNotification, updateExistingNotification }, 
        new BulkWriteOptions { IsOrdered = true })
    .ConfigureAwait(false);

被链接为骗子的帖子绝对有帮助,但这不是答案.有一些事情需要发现.

The post linked as being a dupe was absolutely helpful, but it was not the answer. There were a few things that needed to be discovered.

  • 链接示例中的第二条语句"不起作用 正确,至少在字面上翻译时.为了使其正常工作,我必须在 元素,然后将其包装在Not()过滤器中以反转逻辑.

  • The 'second statement' in the linked example didn't work correctly, at least when translated literally. To get it to work, I had to match on the element and then invert the logic by wrapping it in the Not() filter.

为了在比赛中使用此索引",您必须使用 数组上的负索引.事实证明,C#驱动程序将 查询为时将任何负索引转换为'$'字符 呈现.

In order to use 'this index' on the match, you have to use a negative index on the array. As it turns out, the C# driver will convert any negative index to the '$' character when the query is rendered.

为了确保它们按顺序运行,您必须包括批量写入 IsOrdered设置为true的选项.

In order to ensure they are run in order, you must include bulk write options with IsOrdered set to true.

这篇关于如何同时上载记录和数组元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆