You are currently browsing legacy 4.1 version of documentation. Click here to switch to the newest 4.2 version.

We can help you with migration to the latest RavenDB

Contact Us Now
see on GitHub

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 a performant and uncostly 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.
    For example:

    • Use Counters for an online election page, to continuously update a Number-Of-Votes Counter for each candidate.
    • 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) do not cause conflicts.
      • 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.
    • Counters 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.

  • Counter Naming Convention

  • Counter Value

    • 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 impact the size of the document.
  • 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

Enabling the Counters Feature

  • Counters management is currently an experimental feature of RavenDB, and is disabled by default.

  • To enable this feature, follow these steps:

    • Open the RavenDB server folder, e.g. C:\Users\Dave\Downloads\RavenDB-4.1.1-windows-x64\Server
    • Open settings.json for editing.
    • Enable the Experimental Features -
      Verify that the json file contains the following line: "Features.Availability": "Experimental"
    • Save settings.json, and restart RavenDB Server.

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.
    • 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
    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.