在Mongodb .Net驱动程序中应用upsert

时间:2018-06-20 10:24:54

标签: c# mongodb

我需要执行原子的“如果不存在添加”逻辑,否则什么也不做,为此我正在使用Upsert。

我的模特:

  public class Person
  {
    [BsonId]
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Title { get; set; }
    public DateTime ReceivedAt { get; set; }
    public List<Person> Children { get; set; }
  }

我的代码:

var person = new Person() { Id = Guid.NewGuid(), Name = "name", Title = "title", ReceivedAt = DateTime.Now };
var result = context.People.FindOneAndUpdateAsync<Person>(
           x => x.Title == person.Title && x.Name == person.Name && x.ReceivedAt <= person.ReceivedAt + TimeSpan.FromMinutes(1),
           Builders<Person>.Update.Combine(),
           new FindOneAndUpdateOptions<Person>() { IsUpsert = true });

上面没有插入的文件不存在,我在做什么错?我需要设置IsUpsert以外的其他东西吗?

1 个答案:

答案 0 :(得分:0)

在您的代码中result的类型为Task<Person>,您在这里错过了await,这就是为什么您没有看到抛出异常的原因。当您将代码更改为:

var result = col.FindOneAndUpdateAsync<Person>(
                   x => x.Title == person.Title && x.Name == person.Name && x.ReceivedAt <= person.ReceivedAt + TimeSpan.FromMinutes(1),
                   Builders<Person>.Update.Combine(),
                   new FindOneAndUpdateOptions<Person>() { IsUpsert = true })
               .GetAwaiter().GetResult(); // or await in front of invocation

您将收到带有以下消息的ArgumentException

  

其他信息:更新必须至少具有1个更新运算符。

因此您不能有空更新。要解决此问题,您可以例如重复使用Title属性,该属性的工作方式与您的代码期望的完全相同。

var result = col.FindOneAndUpdateAsync<Person>(
                   x => x.Title == person.Title && x.Name == person.Name && x.ReceivedAt <= person.ReceivedAt + TimeSpan.FromMinutes(1),
                   Builders<Person>.Update.Set(x => x.Title, person.Title),
                   new FindOneAndUpdateOptions<Person>() { IsUpsert = true }).GetAwaiter().GetResult();

ReceivedAt不会被添加,因为您的lambda表达式会转换为$lte,这不是相等比较(请检查文档here)。您应该在更新部分中明确定义该值。

  

此更新根据参数中的相等性子句创建基础文档,然后应用参数中的更新表达式。来自的比较操作将不会包含在新文档中。