Note -
Redis Geospatial (Geo) is based on Sorted Sets, so the same CRDB development instructions apply to Geo.

Similar to Redis Sets, Redis Sorted Sets are non-repeating collections of Strings. The difference between the two is that every member of a Sorted Set is associated with a score used to order the Sorted Set from lowest to highest. While members are unique, they may have the same score.

With Sorted Sets, you can quickly add, remove or update elements as well as get ranges by score or by rank (position). Sorted Sets in CRDBs behave the same and maintain additional metadata to handle concurrent conflicting writes. Conflict resolution is done in two phases:

  1. First, the database resolves conflict at the set level using "OR Set" (Observed-Remove Set). With OR-Set behavior, writes across multiple CRDB instances are typically unioned except in cases of conflicts. Conflicting writes can happen when a CRDB instance deletes an element while the other adds or updates the same element. In this case, an observed Remove rule is followed, and only instances it has already seen are removed. In all other cases, the Add / Update element wins.
  2. Second, the database resolves conflict at the score level. In this case, the score is treated as a counter and applies the same conflict resolution as regular counters.

Please see the following examples to get familiar with Sorted Sets' behavior in CRDB:

Example of Simple Sorted Set with No Conflict:

Time CRDB Instance 1 CRDB Instance 2
t1 ZADD Z 1.1 x
t2 — Sync — — Sync —
t3 ZADD Z 1.2 y
t4 — Sync — — Sync —
t5 ZRANGE Z 0 -1 => x y ZRANGE Z 0 -1 => x y

Explanation: When adding two different elements to a Sorted Set from different replicas (in this example, x with score 1.1 was added by Instance 1 to Sorted Set Z, and y with score 1.2 was added by Instance 2 to Sorted Set Z) in a non-concurrent manner (i.e. each operation happened separately and after both instances were in sync), the end result will be a Sorted Set including both elements in each CRDB instance. Example of Sorted Set and Concurrent Add:

Time CRDB Instance 1 CRDB Instance 2
t1 ZADD Z 1.1 x
t2 ZADD Z 2.1 x
t3 ZSCORE Z x => 1.1 ZSCORE Z x => 2.1
t4 — Sync — — Sync —
t5 ZSCORE Z x => 2.1 ZSCORE Z x => 2.1

Explanation: When concurrently adding an element x to a Sorted Set Z by two different CRDB instances (Instance 1 added score 1.1 and Instance 2 added score 2.1), the CRDB implements Last Write Win (LWW) to determine the score of x. In this scenario, Instance 2 performed the ZADD operation at time t2>t1 and therefore the CRDB will set the score 2.1 to x.

Example of Sorted Set with Concurrent Add Happening at the Exact Same Time:

Time CRDB Instance 1 CRDB Instance 2
t1 ZADD Z 1.1 x ZADD Z 2.1 x
t2 ZSCORE Z x => 1.1 ZSCORE Z x => 2.1
t3 — Sync — — Sync —
t4 ZSCORE Z x => 1.1 ZSCORE Z x => 1.1

Explanation: The example above shows a relatively rare situation, in which two CRDB instances concurrently added the same element x to a Sorted Set at the same exact time but with a different score, i.e. Instance 1 added x with a 1.1 score and Instance 2 added x with a 2.1 score. After syncing, the CRDB realized that both operations happened at the same time and resolved the conflict by arbitrarily (but consistently across all CRDB instances) giving precedence to Instance 1. Example of Sorted Set with Concurrent Counter Increment:

Time CRDB Instance 1 CRDB Instance 2
t1 ZADD Z 1.1 x
t2 — Sync — — Sync —
t3 ZINCRBY Z 1.0 x ZINCRBY Z 1.0 x
t4 — Sync — — Sync —
t5 ZSCORE Z x => 3.1 ZSCORE Z x => 3.1

Explanation: The result is the sum of all ZINCRBY operations performed by all CRDB instances.

Example of Removing an Element from a Sorted Set:

Time CRDB Instance 1 CRDB Instance 2
t1 ZADD Z 4.1 x
t2 — Sync — — Sync —
t3 ZSCORE Z x => 4.1 ZSCORE Z x => 4.1
t4 ZREM Z x ZINCRBY Z 2.0 x
t5 ZSCORE Z x => nill ZSCORE Z x => 6.1
t6 — Sync — — Sync —
t7 ZSCORE Z x => 2.0 ZSCORE Z x => 2.0

Explanation: At t4 - t5, concurrent ZREM and ZINCRBY operations ran on Instance 1 and Instance 2 respectively. Before the instances were in sync, the ZREM operation could only delete what had been seen by Instance 1, so Instance 2 was not affected. Therefore, the ZSCORE operation shows the local effect on x. At t7, after both instances were in-sync, the CRDB resolved the conflict by subtracting 4.1 (the value of element x in Instance 1) from 6.1 (the value of element x in Instance 2).