Counters Overview
-
RavenDB's distributed counters, Counters for short, are numeric data variables that can be added to documents. Use a Counter to count anything that needs counting, like:
- Sold products
- Voting results
- Any event related to the document
-
Counters interact with and can trigger other RavenDB features.
To find out how to use counters with other features, read Counters and Other Features. -
Create and manage Counters using API methods, or through the Studio.
-
In this page:
Why use Counters?
Convenient Counting Mechanism
Counters are very easy to manage, using simple API methods or through the Studio.
E.g. Use counters when you want to -
- Keep track of the number of times a document has been viewed or rated.
- Count how many visitors from certain countries or regions read a document.
- Continuously record the number of visitors on an event page.
- Avoid having to update the whole document for just a numeric value change.
- Have a need for a high-throughput counter (also see Distributed Values below).
Distributed Values
A Counter's value is distributed between cluster nodes.
Among the advantages of this:
- The cluster remains available even when nodes crash.
- Any node can provide or modify a Counter's value immediately, without checking or coordinating this with other nodes.
High Performance, Low Resources
A document includes the Counter's name, while the Counter's actual value is kept in a separate location.
Modifying a Counter's value doesn't require the modification of the document itself.
This results in highly efficient operation.
High-Frequency Counting
Counters are especially useful when a very large number of counting operations is required,
because of their speed and low resources usage.
E.g. Use Counters -
- For an online election page, to continuously update a Number-Of-Votes Counter for each candidate.
- To continuously update Counters with the number of visitors in different sections of a big online store.
Overview
Design
A document's metadata contains only the Counters' names-list for this document.
Counter Values are not kept in the document's metadata, but in a separate location.
Therefore, changes like adding a new counter or deleting an existing counter trigger a document change,
while simply modifying the Counter Value does not.
Cumulative Counter Actions
-
Counter value-modification actions are cumulative, the order in which they are executed doesn't matter.
E.g., It doesn't matter if a Counter has been incremented by 2 and then by 7, or by 7 first and then by 2. -
When a Counter is deleted, the sequence of Counter actions becomes non-cumulative and may require special attention.
Counters and Conflicts
Counter actions (for either name or value) almost never cause conflicts.
The only exception to this is concurrent Delete
and Increment
actions by multiple cluster nodes.
- Counter actions can be executed concurrently or in any order, without causing a conflict.
- You can successfully modify Counters while their document is being modified by a different client.
Counter actions can still be performed when their related documents are in a conflicted state.
Counters Cost
Counters are designated to lower the cost of counting, but do come with a price.
- All the names of a document's Counters are added to its content, increasing its size.
- Counter values occupy storage space.
Be aware that the negligible amount of resources required by a few Counters,
may become significant when there are many.
A single document with thousands of Counters is probably an indication of a modeling mistake,
for example.
Counters Naming Convention
- Valid characters: All visible characters, including Unicode symbols
- Length: Up to 512 bytes
- Encoding: UTF-8
Counter Values
- Valid range: Signed 64-bit integer (-9223372036854775808 to 9223372036854775807)
- Only integer additions are supported (no floats or other mathematical operations).
Number of Counters Per Document
RavenDB doesn't limit the number of Counters you can create.
Note that the Counter names are stored in the document metadata and do impact the size of the document.
The HasCounters
Flag
When a Counter is added to a document, RavenDB automatically sets a HasCounters
Flag in the document's metadata.
When all Counters are removed from a document, the server automatically removes this flag.
Managing Counters
Counter Methods and the CountersFor
Object
Managing Counters is performed using the CountersFor
Session object.
-
Counter methods:
CountersFor.Increment
: Increment the value of an existing Counter, or create a new Counter if it doesn't exist.CountersFor.Delete
: Delete a Counter.CountersFor.Get
: Get the current value of a Counter.CountersFor.GetAll
: Get all the Counters of a document and their values.
-
Usage flow:
- Open a session.
-
Create an instance of
countersFor
.- Either pass
countersFor
an explicit document ID, -or- - Pass it an entity tracked by the session, e.g. a document object
returned from
session.query
or fromsession.load
.
- Either pass
- Use Counter methods to manage the document's Counters.
- If you execute Increment or Delete, call
session.SaveChanges
for the action to take effect on the server.
-
Success and failure:
- As long as the document exists, Counter actions (Increment, Get, Delete etc.) always succeed.
- When a transaction that includes a Counter modification fails for any reason (e.g. a document concurrency conflict), the Counter modification is reverted.
-
CountersFor
usage samples:- You can Use
CountersFor
by explicitly passing it a document ID (without pre-loading the document). - You can also use
CountersFor
by passing it the document object.
- You can Use
// Use CountersFor without loading a document
// 1. Open a session
try (IDocumentSession session = docStore.openSession()) {
// 2. pass an explicit document ID to the countersFor constructor
ISessionDocumentCounters documentCounters = session.countersFor("products/1-C");
// 3. Use `countersFor` methods to manage the product document's Counters
documentCounters.delete("productLikes"); // Delete the "productLikes" Counter
documentCounters.increment("productModified", 15); // Add 15 to Counter "productModified"
Long counter = documentCounters.get("daysLeftForSale");// Get "daysLeftForSale"'s value
// 4. Save changes to the session
session.saveChanges();
}
// Use countersFor by passing it a document object
// 1. Open a session
try (IDocumentSession session = docStore.openSession()) {
// 2. Use the session to load a document.
Product document = session.load(Product.class, "products/1-C");
// 3. Create an instance of `countersFor`
// Pass the document object returned from session.load as a param.
ISessionDocumentCounters documentCounters = session.countersFor(document);
// 4. Use `countersFor` methods to manage the product document's Counters
documentCounters.delete("productLikes"); // Delete the "productLikes" Counter
documentCounters.increment("productModified", 15); // Add 15 to Counter "productModified"
Long counter = documentCounters.get("daysLeftForSale");// Get value of "daysLeftForSale"
// 5. Save the changes to the session
session.saveChanges();
}
Managing Counters using Operations
-
In addition to working with the high-level Session, you can manage Counters using the low-level Operations.
-
CounterBatchOperation can operate on a set of Counters of different documents in a single request.