Mongodb 如何同时插入记录和数组元素?
这意味着要作为双上插操作读取,先上插文档,然后上插数组元素 所以MongoDB对我来说是一个非规范化的存储(我们是事件源代码),我试图处理的事情之一就是它的并发性。问题是:Mongodb 如何同时插入记录和数组元素?,mongodb,mongodb-.net-driver,event-sourcing,Mongodb,Mongodb .net Driver,Event Sourcing,这意味着要作为双上插操作读取,先上插文档,然后上插数组元素 所以MongoDB对我来说是一个非规范化的存储(我们是事件源代码),我试图处理的事情之一就是它的并发性。问题是: 事件的顺序可能不正确,因此对数据库的每次更新都需要进行升级 我不仅需要能够向上插入父文档,还需要能够向上插入该文档的数组属性中的元素 例如: 如果文档不存在,请创建它。此流中的所有事件都具有文档ID,但仅包含部分信息,具体取决于事件 如果文档确实存在,则更新它。这是最简单的部分。update命令只是作为UpdateOn
- 事件的顺序可能不正确,因此对数据库的每次更新都需要进行升级
- 我不仅需要能够向上插入父文档,还需要能够向上插入该文档的数组属性中的元素
- 如果文档不存在,请创建它。此流中的所有事件都具有文档ID,但仅包含部分信息,具体取决于事件
- 如果文档确实存在,则更新它。这是最简单的部分。update命令只是作为UpdateOneAsync和upsert编写的
- 如果事件实际上是要更新列表,则需要升级该列表元素。因此,如果文档不存在,则需要创建该文档,并且列表项将被追加(导致插入);如果文档确实存在,那么我们需要找到该元素并将其更新为upsert,因此如果该元素存在,则将对其进行更新,否则将插入该元素
重申这是一个关于MongoDB C#driver 2.4.x的问题需要一些修改,但我明白了
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);
var notificationData=新的notificationData
{
ReferenceId=e.ReferenceId,
NotificationId=e.NotificationId,
DeliveredDateUtc=e.SentDate.DateTime
};
var matchDocument=Builders.Filter.Eq(s=>s.SurveyId,e.EntityId);
//首先向上插入文档,以确保您有一个要写入的集合
var surveyUpsert=新的更新模型(
匹配文件,
建设者。更新
.SetOnInsert(f=>f.SurveyId,e.EntityId)
.SetOnInsert(f=>f.Notifications,new List()){isupert=true};
//如果现有元素都不匹配,则推送新元素
var noMatchReferenceId=Builders.Filter
.Not(Builders.Filter.ElemMatch(s=>s.Notifications,n=>n.ReferenceId.Equals(e.ReferenceId));
var insertNewNotification=newupdateemodel(
matchDocument和noMatchReferenceId,
建设者。更新
.Push(s=>s.通知、通知数据);
//然后更新与引用ID匹配的元素(如果有)
var matchReferenceId=Builders.Filter
.ElemMatch(s=>s.Notifications,Builders.Filter.Eq(n=>n.ReferenceId,notificationData.ReferenceId));
var updateExistingNotification=new UpdateOneModel(
匹配文档和匹配引用ID,
建设者。更新
//显然,mongo C#驱动程序会将任何负索引转换为索引符号(“$”)
.Set(s=>s.Notifications[-1].NotificationId,e.NotificationId)
.Set(s=>s.Notifications[-1].deliveredateutc,notificationData.deliveredateutc));
//以批处理和顺序执行这些操作
var result=await_surveyRepository.DatabaseCollection
.BulkWriteAsync(
新[]{surveyUpsert,insertNewNotification,updateExistingNotification},
新的BulkWriteOptions{IsOrdered=true})
.配置等待(错误);
这篇文章被链接为一个傻瓜,这绝对是有帮助的,但这不是答案。有一些事情需要被发现
- 链接示例中的“第二个语句”不起作用 正确,至少当逐字翻译时。为了让它发挥作用,我必须在 元素,然后通过将其包装在Not()过滤器中来反转逻辑
- 为了在比赛中使用“此索引”,您必须使用 数组上的负索引。事实证明,C#driver会 执行查询时,将任何负索引转换为“$”字符 渲染
- 为了确保它们按顺序运行,必须包括大容量写入
设置为true的选项IsOrdered
- 做了一些修补,但我成功了
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);
var notificationData=新的notificationData
{
ReferenceId=e.ReferenceId,
NotificationId=e.NotificationId,
DeliveredDateUtc=e.SentDate.DateTime
};
var matchDocument=Builders.Filter.Eq(s=>s.SurveyId,e.EntityId);
//首先向上插入文档,以确保您有一个要写入的集合
var surveyUpsert=新的更新模型(
匹配文件,
建设者。更新
.SetOnInsert(f=>f.SurveyId,e.EntityId)
.SetOnInsert(f=>f.Notifications,new List()){isupert=true};
//如果现有元素都不匹配,则推送新元素
var noMatchReferenceId=Builders.Filter
.Not(Builders.Filter.ElemMatch(s=>s.Notifications,n=>n.ReferenceId.Equals(e.ReferenceId));
var insertNewNotification=newupdateemodel(
matchDocument和noMatchReferenceId,
建设者。更新
.Push(s=>s.通知、通知数据);
//然后更新与引用ID匹配的元素(如果有)
var matchReferenceId=Builders.Filter
.ElemMatch(s=>s.Notifications,Builders.Filter.Eq(n=>n.ReferenceId,notificationData.ReferenceId));
var updateExistingNotification=new UpdateOneModel(
匹配文档和匹配引用ID,
建设者。更新
//显然,mongo C#驱动程序会将任何负索引转换为索引符号(“$”)
.Set(s=>s.Notifications[-1].NotificationId,e.NotificationId)
.Set(s=>s.Notifications[-1].deliveredateutc,notificationData.deliveredateutc));
//以批处理和顺序执行这些操作
var result=await_surveyRepository.DatabaseCollection
.BulkWriteAsync(
新[]{surveyUpsert,insertNewNotification,updateExist