Platform Manual
Data Types
Counter
the counter crdt is a special type intended for use cases where multiple peers need to increment (or decrement) field values at the same time while maintaining consistency; for example, in scenarios such as inventory management and voting there are two methods of modifying an existing counter value the counter type is useful in very select scenarios consider using the set method to define new values on a map to track increments, while also storing additional metadata increment — increases the counter value by the specific number you want to add to the counter value decrement — decreases the counter value by the specific negative value that you want to subtract from the counter common use case a typical exampe for using a counter type four flight attendants walk through an airlane and record passenger meal orders for each seat, they count the number of cans ordered first, the flight attendant selects the flight they are on they then see an interface with each seat in a list view this might be retrieved by an external api, or it could be internal to the app based on some known information about each plane type in a production app, each seat would have a few values that the attendant can modify, but we will just focus on name and orderedcount in this example as each flight attendant walks through the airplane, their devices synchronize together to make sure that each customer only receives one meal if in this case, you used a register type instead of a counter , the value alternates between the latest updated value instead, using a counter merges by taking the sum of each attendant's value if attendant a has sold 100, attendent b has sold 33, and attendant c has sold 98, the value of the counter is 100 + 33 + 98 = 231 in addition to incrementing counters, you can also decrement a counter there is no mechanism preventing a counter from reaching a negative value for example, if the initial count is 1 and two attendants decrement the count by 1 concurrently, the result is 1 creating a counter to create a counter , use the upsert method to ensure the document exists in ditto, and then use the update method to increment the counter and ensure that the correct and accurate counter value is maintained across all peers during replication do not use the upsert method to increment a counter only modify the counter field within an update clause, as follows define the structure of the counter document using the upsert method, ensure that the document exists before interacting with it if it does not exist, ditto automatically creates the document and initializes the counter with a set value of 0 to increment the counter value, call the update method and pass the value you want to increment the counter by do { let docid = try ditto store\["people"] upsert(\[ "name" "frank", "ownedcars" dittocounter() // here 0 is a number ]) ditto store\["people"] findbyid(docid) update({ mutabledoc in mutabledoc?\["ownedcars"] counter? increment(by 1) }) } catch { //handle error print(error) }val docid = ditto store\["people"] upsert(mapof( "name" to "frank", "ownedcars" to dittocounter() )) ditto store collection("people") findbyid(docid) update { mutabledoc > mutabledoc!!\["ownedcars"] counter!! increment(amount = 1 0) }const frankid = await ditto store collection('people') upsert({ name 'frank', ownedcars 0, // here 0 is a number }) await ditto store collection('people') findbyid(frankid) update((mutabledoc) => { mutabledoc at('ownedcars') set(new counter()) mutabledoc at('ownedcars') counter increment(1) })map\<string, object> content = new hashmap<>(); content put("name", "frank"); content put("ownedcars", new dittocounter()); dittodocumentid docid = ditto store collection("people") upsert(content); ditto store collection("people") findbyid(docid) update(mutdoc > { assertthat(mutdoc) isnotnull(); dittomutablecounter counter = mutdoc get("ownedcars") getcounter(); assertthat(counter) isnotnull(); counter increment(1); });var counter = new dittocounter(); var docid = coll upsert(new dictionary\<string, object> { { "make", "honda" }, { "mileage", counter } }); = coll findbyid(docid) update(mutabledoc => { mutabledoc\["mileage"] counter increment(100); });documentid docid = ditto get store() collection("people") upsert( {{"name", "frank"}, {"ownedcars", counter()}}); ditto get store() collection("people") find by id(docid) update( \[]\(mutabledocument \&doc) { auto counter = doc\["ownedcars"] get counter(); counter >increment(1); });let collection = ditto store() collection("people") unwrap(); let doc id = collection upsert(json!({"name" "frank", "owned cars" dittocounter new()})) unwrap(); collection find by id(doc id) update(|x| { if let some(doc) = x { doc increment("owned cars", 1 0) unwrap(); } }) unwrap(); resetting counter values a counter is capable of recalling its previous increment and decrement calls; however, with a counter there is no concept of time this is true even if you change the type of a counter to another field, such as number, and then back into a counter again given this constraint, avoid resetting counters instead, create new documents or collections that have meaning and encapsulate a period of time if it is essential that you reset the counter to zero (0), make sure to remove the counter from the document before attempting to reset the counter note that if another peer increments the counter at the same time that another peer removes the counter , you may encounter unexpected behavior code example the following snippet demonstrates code for the typical example for a counter described in /#common use case , previous ensure the document exists before interacting with it by calling upsert increment the counter by calling update do not use upsert to increment a counter incrementing a counter using upsert results in the counter resetting to its initial value this is because when you upsert, you're effectively replacing the entire document with a new one that is, each field updates, even the document fields that remain unchanged for more information, see docid\ l2hfjvzuyynu5ahzxhwaj if you need to perform an upsert at a later time, ensure that your counter value remains consistent by excluding it in your upsert operation when the app loads, call populateseats() , and then renderseatlist() since flight attendants keep track of orders, locally populate all known flights with default data that way, flight attendants can start collecting information from te beginning, even without an internet connection or any connection with other peers initialize the counter orderedcount by calling dittocounter() the totalavailable variable is stored in a register ; therefore, the value remains constant and does not change unless you explicitly make an update to it at a later time render the seat list by incrementing the counter when a user selects the plus button on the interface do { let docid = try ditto store\["people"] upsert(\[ "name" "frank", "age" 31, "ownedcars" dittocounter() ]) ditto store\["people"] findbyid(docid) update { mutabledoc in mutabledoc?\["age"] = 32 mutabledoc?\["ownedcars"] counter? increment(by 1) } } catch { //handle error print(error) }ditto store collection("people") findbyid(frankid) update { mutabledoc > mutabledoc? let { it\["age"] set(32) it\["ownedcars"] counter!! increment(amount = 1 0) } }const docid = await ditto store collection('people') upsert({ name 'frank', age 31, ownedcars 0, }) await ditto store collection('people') findbyid(docid) update((mutabledoc) => { mutabledoc at('age') set(32) mutabledoc at('ownedcars') set(new counter()) mutabledoc at('ownedcars') counter increment(1) })// not supported in javavar content = new dictionary\<string, object> { { "name", "bob" }, { "age", 40 }, { "ownedcars", new dittocounter() } }; var docid = ditto store collection("people") upsert(content); ditto store collection("people") findbyid(docid) update(mutabledoc => { mutabledoc\["age"] set(32); mutabledoc\["ownedcars"] counter increment(1); });documentid doc id = ditto get store() collection("people") upsert( {{"name", "frank"}, {"age", 31}, {"ownedcars", counter()}}); ditto get store() collection("people") find by id(doc id) update( \[]\(mutabledocument \&doc) { doc\["age"] set(32); auto counter = doc\["ownedcars"] get counter(); counter >increment(1); });let collection = ditto store() collection("people") unwrap(); let doc id = collection upsert(json!({"name" "frank", "owned cars" dittocounter new()})) unwrap(); collection find by id(doc id) update(|opt doc| { if let some(doc) = opt doc { doc set("age", 32) unwrap(); doc increment("owned cars", 1 0) unwrap(); } }) unwrap(); if you want to notify flight attendants when an item is out of stock and no longer available, compare the number of orders made ( ordercount ) with the total quantity available ( totalavailable ) if the number of orders equals or exceeds the total available quantity, the app signals that the item is no longer in stock