RavenDB:文档中可能不存在的 update/merge 属性 的补丁请求
RavenDB: PatchRequest to update/merge property that may not exist in document
我有一个包含以下域模型的文档:
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" }
但是.. 总有一个"but"。如果数据库中有一个 没有设置 属性 的文档,提供的 补丁将引发错误 说 "Cannot modify value from Settings because it was not found"。
我找不到任何选项来将补丁模式切换为即时设置与修改。并且没有加载所有文档、在应用程序端应用更新和更新数千个文档的选项。
我能看到的唯一合理的选择是在 class 构造函数中为 Settings 属性 创建 Dictionary 实例。
伙计们,你能建议一些其他的选择吗?
P.S。 RavenDB 版本限制为 3.5
完成。您可以在下面找到最终版本。实际上,使用了 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);
我有一个包含以下域模型的文档:
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" }
但是.. 总有一个"but"。如果数据库中有一个 没有设置 属性 的文档,提供的 补丁将引发错误 说 "Cannot modify value from Settings because it was not found"。
我找不到任何选项来将补丁模式切换为即时设置与修改。并且没有加载所有文档、在应用程序端应用更新和更新数千个文档的选项。 我能看到的唯一合理的选择是在 class 构造函数中为 Settings 属性 创建 Dictionary 实例。
伙计们,你能建议一些其他的选择吗?
P.S。 RavenDB 版本限制为 3.5
完成。您可以在下面找到最终版本。实际上,使用了 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);