Send Multiple Commands in a Batch
-
Use the low-level
SingleNodeBatchCommand
to send multiple commands in a single request to the server.
This reduces the number of remote calls and allows several operations to share the same transaction. -
All the commands sent in the batch are executed as a single transaction on the node the client communicated with. If any command fails, the entire batch is rolled back, ensuring data integrity.
-
The commands are replicated to other nodes in the cluster only AFTER the transaction is successfully completed on that node.
-
In this page:
Examples
Send multiple commands - using the Store's request executor:
using (var store = new DocumentStore())
using (store.GetRequestExecutor()
.ContextPool.AllocateOperationContext(out var storeContext))
{
// Define the list of batch commands to execute
var commands = new List<ICommandData>
{
new PutCommandData("employees/999", null, new DynamicJsonValue
{
["FirstName"] = "James",
["@metadata"] = new DynamicJsonValue
{
["@collection"] = "employees"
}
}),
new PatchCommandData("employees/2-A", null, new PatchRequest
{
Script = "this.HomePhone = 'New phone number';"
}, null),
new DeleteCommandData("employees/3-A", null)
};
// Define the SingleNodeBatchCommand command
var batchCommand = new SingleNodeBatchCommand(store.Conventions,
storeContext, commands);
// Execute the batch command,
// all the 3 commands defined in the list will be executed in a single transaction
store.GetRequestExecutor().Execute(batchCommand, storeContext);
// Can access the batch command results:
var commandResults = batchCommand.Result.Results;
Assert.Equal(3, commandResults.Length);
var blittable = (BlittableJsonReaderObject)commandResults[0];
blittable.TryGetMember("Type", out var commandType);
Assert.Equal("PUT", commandType.ToString());
blittable.TryGetMember("@id", out var documentId);
Assert.Equal("employees/999", documentId.ToString());
}
using (var store = new DocumentStore())
using (store.GetRequestExecutor()
.ContextPool.AllocateOperationContext(out var storeContext))
{
// Define the list of batch commands to execute
var commands = new List<ICommandData>
{
new PutCommandData("employees/999", null, new DynamicJsonValue
{
["FirstName"] = "James",
["@metadata"] = new DynamicJsonValue
{
["@collection"] = "employees"
}
}),
new PatchCommandData("employees/2-A", null, new PatchRequest
{
Script = "this.HomePhone = 'New phone number';"
}, null),
new DeleteCommandData("employees/3-A", null)
};
// Define the SingleNodeBatchCommand command
var batchCommand = new SingleNodeBatchCommand(store.Conventions,
storeContext, commands);
// Execute the batch command,
// all the 3 commands defined in the list will be executed in a single transaction
await store.GetRequestExecutor().ExecuteAsync(batchCommand, storeContext);
// Can access the batch command results:
var commandResults = batchCommand.Result.Results;
Assert.Equal(3, commandResults.Length);
var blittable = (BlittableJsonReaderObject)commandResults[0];
blittable.TryGetMember("Type", out var commandType);
Assert.Equal("PUT", commandType.ToString());
blittable.TryGetMember("@id", out var documentId);
Assert.Equal("employees/999", documentId.ToString());
}
Send multiple commands - using the Session's request executor:
-
SingleNodeBatchCommand
can also be executed using the session's request executor. -
Note that the transaction created for the HTTP request when executing
SingleNodeBatchCommand
is separate from the transaction initiated by the session's SaveChanges method, even if both are called within the same code block.
Learn more about transactions in RavenDB in Transaction support.
using (var session = store.OpenSession())
{
// Define the list of batch commands to execute
var commands = new List<ICommandData>
{
new PutCommandData("employees/999", null, new DynamicJsonValue
{
["FirstName"] = "James",
["@metadata"] = new DynamicJsonValue
{
["@collection"] = "employees"
}
}),
new PatchCommandData("employees/2-A", null, new PatchRequest
{
Script = "this.HomePhone = 'New phone number';"
}, null),
new DeleteCommandData("employees/3-A", null)
};
// Define the SingleNodeBatchCommand command
var batchCommand = new SingleNodeBatchCommand(store.Conventions,
session.Advanced.Context, commands);
// Execute the batch command,
// all the 3 commands defined in the list will be executed in a single transaction
session.Advanced.RequestExecutor.Execute(batchCommand, session.Advanced.Context);
// Can access the batch command results:
var commandResults = batchCommand.Result.Results;
Assert.Equal(3, commandResults.Length);
var blittable = (BlittableJsonReaderObject)commandResults[0];
blittable.TryGetMember("Type", out var commandType);
Assert.Equal("PUT", commandType.ToString());
blittable.TryGetMember("@id", out var documentId);
Assert.Equal("employees/999", documentId.ToString());
}
using (var session = store.OpenAsyncSession())
{
// Define the list of batch commands to execute
var commands = new List<ICommandData>
{
new PutCommandData("employees/999", null, new DynamicJsonValue
{
["FirstName"] = "James",
["@metadata"] = new DynamicJsonValue
{
["@collection"] = "employees"
}
}),
new PatchCommandData("employees/2-A", null, new PatchRequest
{
Script = "this.HomePhone = 'New phone number';"
}, null),
new DeleteCommandData("employees/3-A", null)
};
// Define the SingleNodeBatchCommand command
var batchCommand = new SingleNodeBatchCommand(store.Conventions,
session.Advanced.Context, commands);
// Execute the batch command,
// all the 3 commands defined in the list will be executed in a single transaction
await session.Advanced.RequestExecutor.ExecuteAsync(
batchCommand, session.Advanced.Context);
// Can access the batch command results:
var commandResults = batchCommand.Result.Results;
Assert.Equal(3, commandResults.Length);
var blittable = (BlittableJsonReaderObject)commandResults[0];
blittable.TryGetMember("Type", out var commandType);
Assert.Equal("PUT", commandType.ToString());
blittable.TryGetMember("@id", out var documentId);
Assert.Equal("employees/999", documentId.ToString());
}
Available batch commands
The following commands can be sent in a batch via SingleNodeBatchCommand
:
(These commands implement the ICommandData
interface).
- BatchPatchCommandData
- CopyAttachmentCommandData
- CountersBatchCommandData
- DeleteAttachmentCommandData
- DeleteCommandData
- DeleteCompareExchangeCommandData
- DeletePrefixedCommandData
- ForceRevisionCommandData
- IncrementalTimeSeriesBatchCommandData
- JsonPatchCommandData
- MoveAttachmentCommandData
- PatchCommandData
- PutAttachmentCommandData
- PutCommandData
- PutCompareExchangeCommandData
- TimeSeriesBatchCommandData
Syntax
public SingleNodeBatchCommand(
DocumentConventions conventions,
JsonOperationContext context,
List<ICommandData> commands,
BatchOptions options = null)
public class BatchOptions
{
public TimeSpan? RequestTimeout { get; set; }
public ReplicationBatchOptions ReplicationOptions { get; set; }
public IndexBatchOptions IndexOptions { get; set; }
public ShardedBatchOptions ShardedOptions { get; set; }
}
public class ReplicationBatchOptions
{
// If set to true,
// will wait for replication to be performed on at least a majority of DB instances.
public bool WaitForReplicas { get; set; }
public int NumberOfReplicasToWaitFor { get; set; }
public TimeSpan WaitForReplicasTimeout { get; set; }
public bool Majority { get; set; }
public bool ThrowOnTimeoutInWaitForReplicas { get; set; }
}
public sealed class IndexBatchOptions
{
public bool WaitForIndexes { get; set; }
public TimeSpan WaitForIndexesTimeout { get; set; }
public bool ThrowOnTimeoutInWaitForIndexes { get; set; }
public string[] WaitForSpecificIndexes { get; set; }
}
public class ShardedBatchOptions
{
public ShardedBatchBehavior BatchBehavior { get; set; }
}
// Executing `SingleNodeBatchCommand` returns the following object:
// ================================================================
public class BatchCommandResult
{
public BlittableJsonReaderArray Results { get; set; }
public long? TransactionIndex { get; set; }
}
public sealed class BlittableArrayResult
{
public BlittableJsonReaderArray Results { get; set; }
public long TotalResults { get; set; }
public string ContinuationToken { get; set; }
}