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

时间:2019-09-26 15:48:09

标签: c# arrays mongodb upsert

具有以下文档结构

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元素时,我想用到期日期更新它,并添加新元素。如果存在不属于同一类别的现有元素,则应将其单独放置,仅应添加新元素。

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

在此类别中没有替代项时,我尝试过修改过滤器以使其匹配。但是,所有不在选定类别中的现有元素也会被更新,即添加了过期日期。

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

1 个答案:

答案 0 :(得分:1)

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

using MongoDB.Entities;
using System;

namespace StackOverflow
{
    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();
        }
    }
}