Objects

LiveObjects enables you to store shared data as "objects" on a channel, allowing your application data to be synchronized across multiple users and devices in realtime. This document explains the key concepts you need to know when working with objects.

Object Types

LiveObjects provides specialized object types to model your application state. These object types are designed to be conflict-free and eventually consistent, meaning that all operations on them are commutative and converge to the same state across all clients.

LiveMap Object

LiveMap is a key/value data structure similar to a dictionary or JavaScript Map:

  • Keys must be strings
  • Values can be primitive types or references to other objects
  • Supports set and remove operations
  • Concurrent updates to the same key are resolved using last-write-wins (LWW) semantics
JavaScript

Primitive Types

LiveMap supports the following primitive types as values:

  • string
  • number
  • boolean
  • bytes

LiveCounter Object

LiveCounter is a numeric counter type:

  • The value is a double-precision floating-point number
  • Supports increment and decrement operations
JavaScript

Root Object

The root object is a special LiveMap instance which:

  • Implicitly exists on a channel and does not need to be created explicitly
  • Has the special objectId of root
  • Cannot be deleted
  • Serves as the entry point for accessing all other objects on a channel

Access the root object using the getRoot() function:

JavaScript

Reachability

All objects must be reachable from the root object (directly or indirectly). Objects that cannot be reached from the root object will eventually be deleted.

When an object has been deleted, it is no longer usable and calling any methods on the object will fail.

In the example below, the only reference to the counterOld object is replaced on the root. This makes counterOld unreachable and it will eventually be deleted.

JavaScript

Composability

LiveObjects enables you to build complex, hierarchical data structures through composability.

Specifically, a LiveMap can store references to other LiveMap or LiveCounter object instances as values. This allows you to create nested hierarchies of data.

JavaScript

It is possible for the same object instance to be accessed from multiple places in your object tree:

JavaScript

It is also possible that object references form a cycle:

JavaScript

Metadata

Objects include metadata that helps with synchronization, conflict resolution and managing the object lifecycle.

Object IDs

Every object has a unique identifier that distinguishes it from all other objects.

Object IDs follow a specific format:

For example:

This format has been specifically designed to ensure uniqueness in a globally distributed system and includes:

PartDescription
typeThe object type (either map or counter).
hashA base64 string encoded hash derived from the initial value of the object and a random nonce.
timestampA Unix millisecond timestamp denoting the creation time of the object.

Tombstones

Tombstones are markers indicating an object or map entry has been deleted.

  • A tombstone is created for an object when it becomes unreachable from the root object.
  • A tombstone is created for a map entry when it is removed

Tombstones protect against lagging clients from re-introducing a deleted value, ensuring all clients eventually converge on the same state. They are eventually garbage collected after a safe period of time.

Timeserials

When an operation message is published it is assigned a unique logical timestamp called a "timeserial".

This timeserial is stored on map entries in order to implement last-write-wins conflict resolution semantics.

Additionally, all objects store the timeserial of the last operation that was applied to the object. Since Ably operates fully independent data centers, these timeserials are stored on a per-site basis.

Timeserial metadata is used for internal purposes and is not directly exposed in client libraries. However, it can be viewed using the REST API.

Select...