Counters and Other Features
-
This section describes the relationships between Counters and other RavenDB features:
- How Counters are supported by the different features.
- How Counters trigger features' execution.
-
In this page:
- Counters and Indexing
- Counters and Queries
- Counters and Revisions
- Counters and Smuggler
- Counters and Changes API
- Counters and Ongoing Tasks -
Backup
,External replication
,ETL
,Data Subscription
- Counters and Other Features: summary
- Including Counters
- Counters Bulk-Insert
Counters and Indexing
Indexing Counters can speed-up finding them and the documents that contain them.
-
Indexing Counter Values Dynamic indexes (aka auto-indexes) cannot index counter values. To index counter values, create a static index that inherits from
AbstractCountersIndexCreationTask
(see here). -
Indexing Counter Names
Re-indexing due to Counter-name modification is normally rare enough to pause no performance issues.
To index a document's Counters by name, use CounterNamesFor.
Counters and Queries
Create queries using code, or send the server raw queries for execution.
- Either way, you can query Counters by name but not by value.
This is because queries are generally based on indexes, and Counter values are not indexed. -
Counter values can be projected from query results, as demonstrated in the following examples.
This way a client can get Counter values from a query without downloading whole documents. -
Use Session.Query to code queries yourself.
- Returned Counter Value: Accumulated
A Counter's value is returned as a single sum, with no specification of the Counter's value on each node.const session = store.openSession(); const query = session.query({collection: "Products"}) .selectFields("ProductLikes"); const queryResults = query.all(); for (let counterValue in queryResults) { console.log("ProductLikes: " + counterValue); }
- Returned Counter Value: Accumulated
-
Use RawQuery to send the server raw RQL expressions for execution.
-
You can use the
counter
method.
Returned Counter Value: Accumulated -
You can use the
counterRaw
method.
Returned Counter Value: Distributed
A Counter's value is returned as a series of values, each maintained by one of the nodes.- It is not expected of you to use this in your application.
Applications normally use the Counter's overall value, and very rarely refer to the value each node gives it.
- It is not expected of you to use this in your application.
counter
andcounterRaw
samples:
//Various RQL expressions sent to the server using counter() //Returned Counter value is accumulated const rawquery1 = session.advanced .rawQuery("from products as p select counter(p, \"ProductLikes\")") .all(); const rawquery2 = session.advanced .rawQuery("from products select counter(\"ProductLikes\") as ProductLikesCount") .all(); const rawquery3 = session.advanced .rawQuery("from products where PricePerUnit > 50 select Name, counter(\"ProductLikes\")") .all();
//An RQL expression sent to the server using counterRaw() //Returned Counter value is distributed const query = session.advanced .rawQuery("from users as u select counterRaw(u, \"downloads\")") .all();
-
Counters and Revisions
A document revision stores all the document's Counters' names and values.
-
Stored Counter Values: Accumulated
A revision stores a Counter's value as a single sum, with no specification of the Counter's value on each node. -
Revisions-creation can be initiated by Counter-name modification.
- When the Revisions feature is enabled, the creation or deletion of a Counter initiates the creation of a new document revision.
- Counter value modifications do not cause the creation of new revisions.
Counters and Smuggler
Smuggler is a DocumentStore property, that can be used to export chosen database items to an external file or to import database items from an existing file into the database.
- Transferred Counter Value: Distributed
Smuggler transfers the entire series of values that the different nodes maintain for a Counter. - To make Smuggler handle Counters, use
DatabaseItemType
entities to import or export.
DatabaseItemType
options:
* None
* Documents
* RevisionDocuments
* Indexes
* Identities
* Tombstones
* LegacyAttachments
* Conflicts
* CompareExchange
* LegacyDocumentDeletions
* LegacyAttachmentDeletions
* DatabaseRecord
* Unknown
* Attachments
* CounterGroups
* Subscriptions
* CompareExchangeTombstones
* TimeSeries
Counters and Changes API
Changes API is a Push service, that can inform you of various changes on the Server, including changes in Counter values.
You can target all Counters, or specify the ones you wish to follow.
- Pushed Counter Value: Accumulated
Changes API
methods return a Counter's value as a single sum, without specifying its value on each node. - The service is initiated by Counter Value Modification.
Counters and Ongoing Tasks:
Each ongoing task relates to Counters in its own way.
-
Counters and the Backup task
There are two backup types: logical-backup and snapshot.
Both types store and restore all data, including Counters.
Both types operate as an ongoing backup routine, with a pre-set time schedule.- Logical Backup:
Backed-up Counter values: Distributed
A logical backup is a higher-level implementation of Smuggler.
As with Smuggler, Counters are backed-up and restored including their values on all nodes. - Snapshot:
A snapshot stores all data and settings as a single binary image. All components, including Counters, are restored to the exact same state they've been at during backup.
- Logical Backup:
-
Counters and the External Replication task
The ongoing external replication task replicates all data, including Counters.-
Replicated Counter Value: Distributed
Counters are replicated along with their values on all nodes. - Replication can be initiated by both Counter-name update and Counter-value modification.
-
Replicated Counter Value: Distributed
-
Counters and the ETL task
ETL is used to export data from RavenDB to an external (either Raven or SQL) database.- SQL ETL is not supported.
Counters cannot be exported to an SQL database over SQL ETL. -
RavenDB ETL is supported.
Counters are exported over RavenDB ETL.- Export can be initiated by both Counter-name update and Counter-value modification.
- Exported Counter Value: Distributed
Counters are exported along with their values on all nodes. - Counters can be exported using a script.
Default behavior: When an ETL script is not provided, Counters are exported.
- SQL ETL is not supported.
-
Counters and the Data Subscriptions task
Data Subscriptions can be initiated by document changes, including those caused by Counter Name updates.
Documents will not be delivered in reaction to Counter Value modification.
Counters and Other Features: Summary
Use this table to find if and how various RavenDB features are triggered by Counters, and how the various features handle Counter values.
-
In the Triggered By column:
- Document Change - Feature is triggered by a Counter Name update.
- Countrer Value Modification - Feature is triggered by a Counter Value modification.
- Time Schedule - Feature is invoked by a pre-set time routine.
- No Trigger - Feature is executed manually, through the Studio or by a Client.
-
In the Counter Value column:
- Accumulated - Counter Value is handled as a single accumulated sum.
- Distributed - Counter Value is handled as a series of values maintained by cluster nodes.
Feature | Triggered by | Counter Value |
---|---|---|
Indexing | Document Change | doesn't handle values |
LINQ Queries | No trigger | Accumulated |
Raw Queries | No trigger | counter() - Accumulated counterRaw() - Distributed |
Smuggler | No trigger | Distributed |
Backup Task | Time Schedule | Distributed |
RavenDB ETL Task | Document Change, Countrer Value Modification |
Distributed |
External Replication task | Document Change, Countrer Value Modification |
Distributed |
Data Subscriptions Update Task | Document Change | |
Changes API | Countrer Value Modification | Accumulated |
Revision creation | Document Change | Accumulated |
Including Counters
You can include Counters while loading a document.
An included Counter is retrieved in the same request as its owner-document and is held by the session,
so it can be immediately retrieved when needed with no additional remote calls.
-
Including Counters when using Session.Load:
- Include a single Counter using
IncludeCounter
. - Include multiple Counters using
IncludeCounters
.
IncludeCounter
andIncludeCounters
usage samples:
const productPage = await session.load("orders/1-A", { includes: includeBuilder => includeBuilder .includeDocuments("products/1-C") .includeCounters(["ProductLikes", "ProductDislikes"]) });
const productPage = await session.load("orders/1-A", { documentType: Product, includes: includeBuilder => includeBuilder.includeDocuments("products/1-C") .includeCounters(["ProductLikes", "ProductDislikes"]) } );
- Include a single Counter using
-
Including Counters when using Session.Query:
- Include a single Counter using
IncludeCounter
. - Include multiple Counters using
IncludeCounters
.
IncludeCounter
andIncludeCounters
usage samples:
const query = session.query({collection: "Product"}) .include(includeBuilder => includeBuilder.includeCounter("ProductLikes"));
const query = session.query({collection: "Product"}) .include(includeBuilder => includeBuilder.includeCounters("ProductLikes", "ProductDownloads"));
- Include a single Counter using
Counters Bulk-Insert
store.BulkInsert
is RavenDB's high-performance data insertion operation.
Use its CountersFor
interface's Increment
method to add or update counters with great speed.
-
Usage
-
countersFor
const counter = session.countersFor("documentid")
Parameters Type Description id
string
Document ID -
increment
const incerment = store.openSession(); session.countersFor("documentid").increment("likes", 100);
Parameters Type Description name
string
Counter Name delta
long
Default: 1L
-
-
Usage Flow
- Create a
store.BulkInsert
instance. - Pass the instance's
CountersFor
interface, the document ID - Call
Increment
as many times as you like. Pass it -
The Counter Name and Value (delta to be added).
- Create a
-
Usage Sample
In this sample, we attach a counter to all User documents.const query = session.query({collection: "User"}) .whereBetween("Age", 0, 30) const result = query.all(); const bulkInsert = store.bulkInsert(); for (let user = 0; user < result.length; user++) { let userId = result[user].id; // Choose document let countersFor = bulkInsert.countersFor(userId); // Add or Increment a counter await bulkInsert.countersFor(userId).increment("downloaded", 100); }