这意味着要作为双重upsert操作读取,然后将文档插入数组元素。
所以MongoDB对我来说是一个非规范化的商店(我们的事件来源),而我试图处理的其中一件事就是它的并发性。问题是:
例如:
如果可能的话,让它作为单个原子操作执行将是理想的,但如果它只能在多个步骤中完成,那么就这样吧。由于2.x驱动程序发生了很大的变化,我在网上得到了很多混合的例子。不确定我在UpdateOneAsync之外寻找什么。目前使用2.4.x.解释的例子将不胜感激。 TIA
注意: 重申这是关于MongoDB C#驱动程序2.4.x的问题
答案 0 :(得分:1)
做了一些修补,但我明白了。
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);
作为一个骗局链接的帖子绝对有帮助,但它不是答案。有一些事情需要发现。
第二个陈述&#39;在链接的例子中没有工作 正确的,至少在字面翻译时。为了让它发挥作用,我不得不匹配 元素然后通过将其包装在Not()过滤器中来反转逻辑。
为了使用&#39;这个索引&#39;在比赛中,你必须使用一个 数组上的负索引。事实证明,C#驱动程序会 将任何否定索引转换为&#39; $&#39;查询时的字符 呈现。
为了确保它们按顺序运行,您必须包括批量写入
IsOrdered
设置为true的选项。