我试图进行一个数据库调用,以将元素添加到嵌套数组中,或者如果该元素已经存在,则增加一个计数器。在这种情况下,我们尝试查看是否存在匹配的子文档,如果找不到匹配的子文档,我们希望将该子文档添加到“子文档”列表中,如果找到一个子文档,我们希望增加在该列表中找到的子文档的计数属性。
我们之所以要寻找一个电话来这样做,是因为我们将有多种服务可能试图同时做同一件事。
public class Document
{
[BsonId]
[BsonIgnoreIfDefault]
[BsonRepresentation(BsonType.ObjectId)]
public string DocumentID { get; set; }
public int Date { get; set; }
public List<SubDocument> SubDocs { get; set; }
}
public class SubDocument
{
public string Count { get; set; }
public string Name { get; set; }
}
任何帮助将不胜感激。我们正在使用.NET驱动程序2.8.1
我可以使用查找来执行此操作,如果找到,则会更新计数器。但是到目前为止的测试显示,如果有多个服务这样做的话,计数将会被遗漏。
答案 0 :(得分:2)
这可以通过单个bulkWrite
命令来完成,该命令结合了2条这样的更新命令:
db.Document.bulkWrite([
{ updateOne: {
filter: {
"_id": ObjectId("5d455b8f2d686e2980829d1b"),
"SubDocs": {
"$not": {
"$elemMatch": {
"Name": "iron man" } } } },
update: {
"$push": {
"SubDocs": {
"Count": NumberInt("0"),
"Name": "iron man" } } } }
},
{ updateOne: {
filter: {
"_id": ObjectId("5d455b8f2d686e2980829d1b"),
"SubDocs": {
"$elemMatch": {
"Name": "iron man"
} } },
update: {
"$inc": {
"SubDocs.$.Count": NumberInt("1")
} } } }])
这是一个多线程测试程序,在我的开发环境中似乎没有任何并发问题。
using MongoDB.Entities; // PM> Install-Package MongoDB.Entities
using System.Linq;
using System.Threading.Tasks;
namespace StackOverflow
{
public class Document : Entity
{
public SubDocument[] SubDocs { get; set; } = new SubDocument[] { };
}
public class SubDocument
{
public int Count { get; set; }
public string Name { get; set; }
}
public class Program
{
private static void Main(string[] args)
{
new DB("test");
var doc = new Document();
doc.Save();
var subDoc = new SubDocument { Name = "iron man" };
Parallel.ForEach(Enumerable.Range(1, 20), _ =>
{
var bulk = DB.Update<Document>();
bulk.Match(d =>
d.ID == doc.ID &&
!d.SubDocs.Any(s => s.Name == subDoc.Name))
.Modify(b => b.Push(d => d.SubDocs, subDoc))
.AddToQueue();
bulk.Match(d =>
d.ID == doc.ID &&
d.SubDocs.Any(s => s.Name == subDoc.Name))
.Modify(b =>
b.Inc(d => d.SubDocs[-1].Count, 1))
.AddToQueue();
bulk.Execute();
});
}
}
}
答案 1 :(得分:0)
我相信Mongo 4 has support for atomic transactions,因此探索之路就是尝试并使用它们。
如果要在C#端执行此操作,则在执行检查文档是否存在/更新计数器的逻辑时,确保一次仅更新一项服务的一种方法是包装关键部分中的逻辑(即锁定)。
请查看https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement,以获取有关操作方法的示例。