Skip to main content

Counters

If you have a numeric value that is only ever changed by adding or subtracting (e.g. counting how many times the user has done a particular thing), you should use the Automerge.Counter datatype instead of a plain number, because it deals with concurrent changes correctly.

Note: Using the Automerge.Counter datatype is safer than changing a number value yourself using the ++ or += 1 operators. For example, suppose the value is currently 3:

  • If two users increment it concurrently, they will both register 4 as the new value, whereas the two increments should result in a value of 5.
  • If one user increments twice and the other user increments three times before the documents are merged, we will now have conflicting changes (5 vs. 6), rather > than the desired value of 8 (3 + 2 + 3).

To set up a Counter:

state = Automerge.change(state, (doc) => {
// The counter is initialized to 0 by default. You can pass a number to the
// Automerge.Counter constructor if you want a different initial value.
doc.buttonClicks = new Automerge.Counter();
});

To get the current counter value, use doc.buttonClicks.value. Whenever you want to increase or decrease the counter value, you can use the .increment() or .decrement() method:

state = Automerge.change(state, (doc) => {
doc.buttonClicks.increment(); // Add 1 to counter value
doc.buttonClicks.increment(4); // Add 4 to counter value
doc.buttonClicks.decrement(3); // Subtract 3 from counter value
});

Note: In relational databases it is common to use an auto-incrementing counter to generate primary keys for rows in a table, but this is not safe in Automerge, since several users may end up generating the same counter value! Instead it is best to use UUIDs to identify entities.