Operations: Counters: Batch

CounterBatchOperation allows you to operate on multiple counters (INCREMENT, GET, DELETE) of different documents in a single request.

Syntax

public CounterBatchOperation(CounterBatch counterBatch)
Parameters
counterBatch CounterBatch An object that holds a list of DocumentCountersOperation. Each element in the list describes the counter operations to perform for a specific document

public class CounterBatch {
    private boolean replyWithAllNodesValues;
    private List<DocumentCountersOperation> documents = new ArrayList<>();
    private boolean fromEtl;

    // getters and setters
}

DocumentCountersOperation

public class DocumentCountersOperation {
    private List<CounterOperation> operations;
    private String documentId;

    // getters and setters
}

CounterOperation

public static class CounterOperation {
    private CounterOperationType type;
    private String counterName;
    private long delta; // the value to increment by

    // getters and setters
}

CounterOperationType

public enum CounterOperationType {
    NONE,
    INCREMENT,
    DELETE,
    GET,
    PUT
}

Document updates as a result of a counter operation

A document that has counters holds all its counter names in the metadata.
Therefore, when creating a new counter, the parent document is modified, as the counter's name needs to be added to the metadata.
Deleting a counter also modifies the parent document, as the counter's name needs to be removed from the metadata.
Incrementing an existing counter will not modify the parent document.

Even if a DocumentCountersOperation contains several CounterOperation items that affect the document's metadata (create, delete), the parent document will be modified only once, after all the CounterOperation items in this DocumentCountersOperation have been processed.
If DocumentCountersOperation doesn't contain any CounterOperation that affects the metadata, the parent document won't be modified.

Return Value

CounterBatchOperation returns a CountersDetail object, which holds a list of CounterDetail objects

public class CountersDetail {

    private List<CounterDetail> counters;

    // getters and setters
}

public class CounterDetail {
    private String documentId; // ID of the document that holds the counter
    private String counterName; // The counter name
    private long totalValue; // Total counter value
    private long etag; // Counter Etag
    private Map<String, Long> counterValues; // A map of counter values per database node

    private String changeVector; // Change vector of the counter

    // getters and setters
}

If a CounterOperationType is INCREMENT or GET, a CounterDetail object will be added to the result.
DELETE operations will not be included in the result.

Examples

Assume we have two documents, "users/1" and "users/2", that hold 3 counters each -
"likes", "dislikes" and "downloads" - with values 10, 20 and 30 (respectively)

Example #1 : Increment Multiple Counters in a Batch

DocumentCountersOperation operation1 = new DocumentCountersOperation();
operation1.setDocumentId("users/1");
operation1.setOperations(Arrays.asList(
    CounterOperation.create("likes", CounterOperationType.INCREMENT, 5),
    CounterOperation.create("dislikes", CounterOperationType.INCREMENT) // Delta not specified, increment by 1
));

DocumentCountersOperation operation2 = new DocumentCountersOperation();
operation2.setDocumentId("users/2");
operation2.setOperations(Arrays.asList(
    CounterOperation.create("likes", CounterOperationType.INCREMENT, 100),

    // this will create a new counter "score", with initial value 50
    // "score" will be added to counter-names in "users/2" metadata
    CounterOperation.create("score", CounterOperationType.INCREMENT, 50)
));

CounterBatch counterBatch = new CounterBatch();
counterBatch.setDocuments(Arrays.asList(operation1, operation2));
store.operations().send(new CounterBatchOperation(counterBatch));

Result:

{
	"Counters": 
    [
		{
			"DocumentId" : "users/1",
			"CounterName" : "likes",
			"TotalValue" : 15,
			"CounterValues" : null
		},
        {
			"DocumentId" : "users/1",
			"CounterName" : "dislikes",
			"TotalValue" : 21,
			"CounterValues" : null
		},
        {
			"DocumentId" : "users/2",
			"CounterName" : "likes",
			"TotalValue" : 110,
			"CounterValues" : null
		},
        {
			"DocumentId" : "users/2",
			"CounterName" : "score",
			"TotalValue" : 50,
			"CounterValues" : null
		}
	]
}

Example #2 : Get Multiple Counters in a Batch

DocumentCountersOperation operation1 = new DocumentCountersOperation();
operation1.setDocumentId("users/1");
operation1.setOperations(Arrays.asList(
    CounterOperation.create("likes", CounterOperationType.GET),
    CounterOperation.create("downloads", CounterOperationType.GET)
));

DocumentCountersOperation operation2 = new DocumentCountersOperation();
operation2.setDocumentId("users/2");
operation2.setOperations(Arrays.asList(
    CounterOperation.create("likes", CounterOperationType.GET),
    CounterOperation.create("dislikes", CounterOperationType.GET)
));

CounterBatch counterBatch = new CounterBatch();
counterBatch.setDocuments(Arrays.asList(operation1, operation2));

store.operations().send(new CounterBatchOperation(counterBatch));

Result:

{
	"Counters": 
    [
		{
			"DocumentId" : "users/1",
			"CounterName" : "likes",
			"TotalValue" : 10,
			"CounterValues" : null
		},
        {
			"DocumentId" : "users/1",
			"CounterName" : "downloads",
			"TotalValue" : 30,
			"CounterValues" : null
		},
        {
			"DocumentId" : "users/2",
			"CounterName" : "likes",
			"TotalValue" : 10,
			"CounterValues" : null
		},
        {
			"DocumentId" : "users/2",
			"CounterName" : "dislikes",
			"TotalValue" : 20,
			"CounterValues" : null
		}
	]
}

Example #3 : Delete Multiple Counters in a Batch

DocumentCountersOperation operation1 = new DocumentCountersOperation();
operation1.setDocumentId("users/1");
operation1.setOperations(Arrays.asList(
    // "likes" and "dislikes" will be removed from counter-names in "users/1" metadata
    CounterOperation.create("likes", CounterOperationType.DELETE),
    CounterOperation.create("dislikes", CounterOperationType.DELETE)
));

DocumentCountersOperation operation2 = new DocumentCountersOperation();
operation2.setDocumentId("users/2");
operation2.setOperations(Arrays.asList(
    // "downloads" will be removed from counter-names in "users/2" metadata
    CounterOperation.create("downloads", CounterOperationType.DELETE)
));

CounterBatch counterBatch = new CounterBatch();
counterBatch.setDocuments(Arrays.asList(operation1, operation2));
store.operations().send(new CounterBatchOperation(counterBatch));

Result:

{
	"Counters": []
}

Example #4 : Mix Different Types of CounterOperations in a Batch

DocumentCountersOperation operation1 = new DocumentCountersOperation();
operation1.setDocumentId("users/1");
operation1.setOperations(Arrays.asList(
    CounterOperation.create("likes", CounterOperationType.INCREMENT, 10),
    CounterOperation.create("dislikes", CounterOperationType.GET),
    CounterOperation.create("downloads", CounterOperationType.DELETE)
));

DocumentCountersOperation operation2 = new DocumentCountersOperation();
operation2.setDocumentId("users/2");
operation2.setOperations(Arrays.asList(
    CounterOperation.create("likes", CounterOperationType.GET),
    CounterOperation.create("dislikes", CounterOperationType.DELETE)
));

CounterBatch counterBatch = new CounterBatch();
counterBatch.setDocuments(Arrays.asList(operation1, operation2));
store.operations().send(new CounterBatchOperation(counterBatch));

Result:

{
	"Counters": 
    [
		{
			"DocumentId" : "users/1",
			"CounterName" : "likes",
			"TotalValue" : 20,
			"CounterValues" : null
		},
        {
			"DocumentId" : "users/1",
			"CounterName" : "dislikes",
			"TotalValue" : 20,
			"CounterValues" : null
		},
        {
			"DocumentId" : "users/2",
			"CounterName" : "likes",
			"TotalValue" : 10,
			"CounterValues" : null
		}
	]
}