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