Counters: Overview


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


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:
Method Name Description
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.
    • 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.

    // Use CountersFor without loading a document
    
    // 1. Open a session
    using (var session = docStore.OpenSession())
    {
        // 2. pass an explicit document ID to the CountersFor constructor 
        var 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"
        var 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
    using (var session = docStore.OpenSession())
    {
        // 2. Use the session to load a document.
        var document = session.Load<Product>("products/1-C");
    
        // 3. Create an instance of `CountersFor`
        //   Pass the document object returned from session.Load as a param.
        var 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"
        var 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.