Commands: Patches: How to use JavaScript to patch your documents?
Patch command is used to perform partial document updates without having to load, modify, and save a full document. This is usually useful for updating denormalized data in entities.
Syntax
/// <summary>
/// Sends a patch request for a specific document, ignoring document's Etag and if it is missing
/// </summary>
/// <param name="key">Key of the document to patch</param>
/// <param name="patch">The patch request to use (using JavaScript)</param>
RavenJObject Patch(string key, ScriptedPatchRequest patch);
/// <summary>
/// Sends a patch request for a specific document, ignoring the document's Etag
/// </summary>
/// <param name="key">Key of the document to patch</param>
/// <param name="patch">The patch request to use (using JavaScript)</param>
/// <param name="ignoreMissing">true if the patch request should ignore a missing document, false to throw DocumentDoesNotExistException</param>
RavenJObject Patch(string key, ScriptedPatchRequest patch, bool ignoreMissing);
/// <summary>
/// Sends a patch request for a specific document
/// </summary>
/// <param name="key">Key of the document to patch</param>
/// <param name="patch">The patch request to use (using JavaScript)</param>
/// <param name="etag">Require specific Etag [null to ignore]</param>
RavenJObject Patch(string key, ScriptedPatchRequest patch, Etag etag);
/// <summary>
/// Sends a patch request for a specific document which may or may not currently exist
/// </summary>
/// <param name="key">Id of the document to patch</param>
/// <param name="patchExisting">The patch request to use (using JavaScript) to an existing document</param>
/// <param name="patchDefault">The patch request to use (using JavaScript) to a default document when the document is missing</param>
/// <param name="defaultMetadata">The metadata for the default document when the document is missing</param>
RavenJObject Patch(string key, ScriptedPatchRequest patchExisting, ScriptedPatchRequest patchDefault, RavenJObject defaultMetadata);
Parameters
public class ScriptedPatchRequest
{
/// <summary>
/// JavaScript function that will patch a document
/// </summary>
/// <value>The type.</value>
public string Script { get; set; }
/// <summary>
/// Additional values that will be passed to function
/// </summary>
public Dictionary<string, object> Values { get; set; }
}
Methods, objects and variables
Before we will move to the examples, let's look at the methods, objects, and variables available:
__document_id |
variable | Id for current document |
this |
object | Current document (with metadata) |
LoadDocument(key) |
method | Allows document loading, increases maximum number of allowed steps in script. See Raven/AdditionalStepsForScriptBasedOnDocumentSize here. |
PutDocument(key, data, metadata) |
method | Allows document putting, returns generated key |
IncreaseNumberOfAllowedStepsBy(number) |
method | Will increase the maximum allowed number of steps in script by given value. Only available if Raven/AllowScriptsToAdjustNumberOfSteps is set to true . |
_ |
object | Lo-Dash 2.4.1 |
trim() |
string.prototype | trims the string e.g. this.FirstName.trim() |
output(...) |
method | Allows debug your patch, prints passed messages in output tab |
indexOf(...) |
Array.prototype | wrapper for _.indexOf |
filter(...) |
Array.prototype | wrapper for _.filter |
Map(...) |
Array.prototype | wrapper for _.map |
Where(...) |
Array.prototype | wrapper for _.filter |
RemoveWhere(...) |
Array.prototype | wrapper for _.remove returning Array for easier chaining |
Remove(...) |
Array.prototype | wrapper for _.pull returning Array for easier chaining |
Custom functions
Beside built-in functions, custom ones can be introduced. Please visit this page if you want to know how to add custom functions.
Example I
// change FirstName to Robert
store
.DatabaseCommands
.Patch(
"employees/1",
new ScriptedPatchRequest
{
Script = "this.FirstName = 'Robert';"
});
Example II
// trim FirstName
store
.DatabaseCommands
.Patch(
"employees/1",
new ScriptedPatchRequest
{
Script = "this.FirstName = this.FirstName.trim();"
});
Example III
// add new property Age with value of 30
store
.DatabaseCommands
.Patch(
"employees/1",
new ScriptedPatchRequest
{
Script = "this.Age = 30;"
});
Example IV
// add new property Age with value of 30 using LoDash
store
.DatabaseCommands
.Patch(
"employees/1",
new ScriptedPatchRequest
{
Script = "_.extend(this, { 'Age': '30'});"
});
Example V
// passing data and loading different document
store
.DatabaseCommands
.Patch(
"employees/1",
new ScriptedPatchRequest
{
Script = @"
var employee = LoadDocument(differentEmployeeId);
this.FirstName = employee.FirstName;",
Values = new Dictionary<string, object>
{
{ "differentEmployeeId", "employees/2" }
}
});
Example VI
// accessing metadata (added ClrType property with value from @metadata)
store
.DatabaseCommands
.Patch(
"employees/1",
new ScriptedPatchRequest
{
Script = @"this.ClrType = this['@metadata']['Raven-Clr-Type'];"
});
Example VII
// creating new document with auto-assigned key e.g. 'Comments/100'. Document key will be returned by PutDocument.
store
.DatabaseCommands
.Patch(
"employees/1",
new ScriptedPatchRequest
{
Script = @"var commentKey = PutDocument('Comments/', { 'Author': this.LastName }, { });"
});
Example VIII
// add a new comment to Comments
store
.DatabaseCommands
.Patch(
"blogposts/1",
new ScriptedPatchRequest
{
Script = @"this.Comments.push({ 'Title': 'Some title', 'Content': 'Lore ipsum' });"
});
Example IX
// removing comments with 'Some title' as a title
store
.DatabaseCommands
.Patch(
"blogposts/1",
new ScriptedPatchRequest
{
Script = @"
this.Comments.RemoveWhere(function(comment) {
return comment.Title == 'Some title';
});"
});
Example X
// modifying each comment
store
.DatabaseCommands
.Patch(
"blogposts/1",
new ScriptedPatchRequest
{
Script = @"
this.Comments.Map(function(comment) {
comment.Title = 'New title';
return comment;
});"
});
Example XI
// increasing maximum number of allowed steps
store
.DatabaseCommands
.Patch(
"employees/1",
new ScriptedPatchRequest
{
Script = @"
var employee = LoadDocument(differentEmployeeId);
if (employee) {
IncreaseNumberOfAllowedStepsBy(10);
this.FirstName = employee.FirstName;
}",
Values = new Dictionary<string, object>
{
{ "differentEmployeeId", "employees/2" }
}
});