RavenDB:PatchRequest更新/合并文档

时间:2018-07-26 11:59:26

标签: c# .net database nosql ravendb

我有一个具有以下域模型的文档:

class Entity
{
    ...
    Dictionary<string, string> Settings { get; set; }
    ...
}

并且需要更新指定的集合。但是 不覆盖 - 合并 ,并包含传入的更新。由于我需要以这种方式处理成千上万的文档,因此选择了 PatchCommand 以获得更好的性能。得到了:

new PatchCommandData
{
    Key = upd.EntityId,
    Patches = new[]
    {
        // Foreach incoming Setting remove existing value (if any) and add the new one
        new PatchRequest
        {
            Type = PatchCommandType.Modify,
            Name = nameof(Entity.Settings),
            Nested = upd.UpdatedSettings.Keys
                .Select(x => new PatchRequest
                {
                    Type = PatchCommandType.Unset,
                    Name = x
                })
                .ToArray()
                .Union(upd.UpdatedSettings.Keys
                .Select(x => new PatchRequest
                {
                    Type = PatchCommandType.Set,
                    Name = x,
                    Value = upd.UpdatedSettings[x]
                })
                .ToList())
                .ToArray(),
            Value = RavenJToken.FromObject(upd.UpdatedSettings)
        }
    }
}

通过这种方式执行下一次更新:

Before: { Setting1 = "Value1", Setting2 = "Value2" }
Update request: { Setting2 = "NewValue2", Setting3 = "Value3" }
After: { Setting1 = "Value1", Setting2 = "NewValue2", Setting3 = "Value3" }

但是。总是有一个“但是”。如果db中有一个文档,但没有Settings属性,则提供的 patch将引发错误,提示“无法从Settings修改值,因为找不到它”。

我找不到任何选项可以随时将补丁程序模式切换为“设置与​​修改”。而且没有选项可以加载所有文档,在应用程序端应用更新并更新数千个文档。 我可以看到的唯一合理的选择是在类构造函数中为Settings属性创建Dictionary实例。

伙计,您还能提出其他建议吗?

P.S。 RavenDB版本限制为3.5

1 个答案:

答案 0 :(得分:0)

完成。您可以在下面找到最终版本。实际上,使用了ScriptedPatchCommandData。它包含JavaScript主体,Raven会对文件进行评估并执行。从性能的角度来看,它不是最佳选择。但事实证明,这并不重要。希望对某人有帮助。

const string fieldParameterName = "fieldName";
const string valueParameterName = "value";

var patch = updates
    .Select(update => new ScriptedPatchCommandData
    {
        Key = update.EntityId,
        Patch = new ScriptedPatchRequest
        {
            Script = $"this[{fieldParameterName}] = _.assign({{}}, this[{fieldParameterName}], JSON.parse({valueParameterName}));",
            Values = new Dictionary<string, object>
            {
                { 
                     fieldParameterName,
                     nameof(Entity.Settings)
                },
                {
                    valueParameterName,
                    JsonConvert.SerializeObject(update.UpdatedSettings)
                }
            }
        }
    })
    .ToList();

return await DocumentStore.AsyncDatabaseCommands.BatchAsync(patch);