C# MongoDb 有条件地更新文档中的现有数组元素并添加新元素

C# MongoDb Conditionally Update Existing Array Elements In Document And Add New Element

具有以下文档结构

public class Disclaimer
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public ObjectId Id { get; set; }

    public List<Override> Overrides { get; set; }
}

public class Override
{
    public int CategoryId { get; set; }
    public DateTime EffectiveDate { get; set; }
    public DateTime? ExpiryDate { get; set; }
    public string Message { get; set; }
}

和查询

var idFilter = Builders<Models.Database.Disclaimer>.Filter.Where(x => x.Id == ObjectId.Parse(id) && x.Overrides.Any(y => y.CategoryId == createOverrideDto.CategoryId)));

var overrideCancellations = Builders<Models.Database.Disclaimer>.Update.Set(x => x.Overrides[-1].ExpiryDate, DateTime.Now);

var update = overrideCancellations.Push(x => x.Overrides, new Models.Database.Override()
  {
    CategoryId = createOverrideDto.CategoryId,
    EffectiveDate = DateTime.Now,
    Message = createOverrideDto.Message
  });

result = _repository.Get().UpdateOne(filter, update);

我想在同一类别中添加新元素时用到期日期更新现有覆盖元素,然后添加新元素。如果存在不在同一类别中的现有元素,则应保留这些元素,仅​​应附加新元素。

如果存在一个或多个具有所选类别的现有 Override 元素,我当前的代码可以正常工作。但是,如果没有,即如果数组为空或所有现有的都不在类别中,则过滤子句不匹配,并且不会运行更新。

我已尝试修改我的过滤器以匹配此类别中没有覆盖的情况。但是,不在所选类别中的任何现有元素也会更新,即添加到期日期。

我可以更改我的文档结构,以便 Overrides 是一个具有类别 ID 字段的对象,然后是单独的数组,但我可能仍然遇到更新插入问题?

您要执行的操作需要使用数组过滤器和 2 个步骤的批量更新。为了简洁起见,这里有一个如何使用 MongoDB.Entities 完成的示例。但它可以直接翻译成官方驱动程序,因为它只是驱动程序的包装器。

using MongoDB.Entities;
using System;

namespace Whosebug
{
    public class Disclaimer : Entity
    {
        public Override[] Overrides { get; set; }
    }

    public class Override
    {
        public int CategoryId { get; set; }
        public DateTime EffectiveDate { get; set; }
        public DateTime? ExpiryDate { get; set; }
        public string Message { get; set; }
    }

    public class Program
    {
        private static void Main(string[] args)
        {
            new DB("test", "localhost");

            // create seed data
            var seed = new Disclaimer
            {
                Overrides = new[]
                {
                    new Override
                    {
                        CategoryId = 666, EffectiveDate = DateTime.Now.AddDays(-1), Message = "disclaimer 1"
                    },
                    new Override
                    {
                        CategoryId = 666, EffectiveDate = DateTime.Now.AddDays(-1), Message = "disclaimer 2"
                    },
                    new Override
                    {
                        CategoryId = 777, EffectiveDate = DateTime.Now.AddDays(-1), Message = "disclaimer 3"
                    }
                }
            }; seed.Save();

            // start bulk update command
            DB.Update<Disclaimer>()

              // step1: set expiry date on existing 666s
              .Match(d => d.ID == seed.ID)
              .WithArrayFilter("{ 'x.CategoryId' : 666 }")
              .Modify(b => b.Set("Overrides.$[x].ExpiryDate", DateTime.Now))
              .AddToQueue()

              // step2: add a new 666
              .Match(d => d.ID == seed.ID)
              .Modify(b => b.Push(d => d.Overrides,
                                         new Override
                                         {
                                             CategoryId = 666,
                                             EffectiveDate = DateTime.Now,
                                             Message = "disclaimer 4"
                                         }))
              .AddToQueue()

              // run two step bulk update command
              .Execute();
        }
    }
}