LiveMap
LiveMap is a key/value data structure that synchronizes its state across users in realtime. It enables you to store primitive values, such as numbers, strings, booleans and buffers, as well as other objects, enabling you to build complex, hierarchical object structure.
Conflicts in a LiveMap are automatically resolved with last-write-wins (LWW) semantics. The latest received operation on a key will be applied to the LiveMap and broadcast to all clients.
Create LiveMap
A LiveMap
instance can be created using the channel.objects.createMap()
method. It must be stored inside another LiveMap
object that is reachable from the root object .
channel.objects.createMap()
is asynchronous, as the client sends the create operation to the Ably system and waits for an acknowledgment of the successful map creation.
const map = await channel.objects.createMap();
await root.set('myMap', map);
CopyCopied!
Optionally, you can specify an initial key/value structure when creating the map:
// Pass a regular JavaScript object reflecting the initial state
const map = await channel.objects.createMap({ foo: 'bar', baz: 42 });
// You can also pass other objects as values for keys
await channel.objects.createMap({ nestedMap: map });
CopyCopied!
Get value for a key
Get the current value for a key in a map using the LiveMap.get()
method:
console.log('Value for my-key:', map.get('my-key'));
CopyCopied!
Subscribe to data updates
You can subscribe to data updates on a map to receive realtime changes made by you or other clients.
Subscribe to data updates on a map using the LiveMap.subscribe()
method:
map.subscribe((update) => {
console.log('Map updated:', [...map.entries()]);
console.log('Update details:', update);
});
CopyCopied!
The update object provides details about the change, listing the keys that were changed and indicating whether they were updated (value changed) or removed from the map.
Example structure of an update object when the key foo
is updated and the key bar
is removed:
{
{
"foo": "updated",
"bar": "removed"
}
}
CopyCopied!
Use the unsubscribe()
function returned in the subscribe()
response to remove a map update listener:
// Initial subscription
const { unsubscribe } = map.subscribe(() => console.log('Map updated'));
// To remove the listener
unsubscribe();
CopyCopied!
Use the LiveMap.unsubscribe()
method to deregister a provided listener:
// Initial subscription
const listener = () => console.log('Map updated');
map.subscribe(listener);
// To remove the listener
map.unsubscribe(listener);
CopyCopied!
Use the LiveMap.unsubscribeAll()
method to deregister all map update listeners:
map.unsubscribeAll();
CopyCopied!
Set keys in a LiveMap
Set a value for a key in a map by calling LiveMap.set()
. This operation is synchronized across all clients and triggers data subscription callbacks for the map, including on the client making the request.
Keys in a map can contain numbers, strings, booleans and buffers, as well as other LiveMap
and LiveCounter
objects.
This operation is asynchronous, as the client sends the corresponding update operation to the Ably system and waits for acknowledgment of the successful map key update.
await map.set('foo', 'bar');
await map.set('baz', 42);
// Can also set a reference to another object
const counter = await channel.objects.createCounter();
await map.set('counter', counter);
CopyCopied!
Remove a key from a LiveMap
Remove a key from a map by calling LiveMap.remove()
. This operation is synchronized across all clients and triggers data subscription callbacks for the map, including on the client making the request.
This operation is asynchronous, as the client sends the corresponding remove operation to the Ably system and waits for acknowledgment of the successful map key removal.
await map.remove('foo');
CopyCopied!
Iterate over key/value pairs
Iterate over key/value pairs, keys or values using the LiveMap.entries()
, LiveMap.keys()
and LiveMap.values()
methods respectively.
These methods return a map iterator object for convenient traversal. Note that contrary to JavaScript’s Map counterpart, these methods do not guarantee that entries are returned in insertion order.
for (const [key, value] of map.entries()) {
console.log(`Key: ${key}, Value: ${value}`);
}
for (const key of map.keys()) {
console.log(`Key: ${key}`);
}
for (const value of map.values()) {
console.log(`Value: ${value}`);
}
CopyCopied!
Subscribe to lifecycle events on a map using the LiveMap.on()
method:
map.on('deleted', () => {
console.log('Map has been deleted');
});
CopyCopied!
Read more about objects lifecycle events.
Use the off()
function returned in the on()
response to remove a lifecycle event listener:
// Initial subscription
const { off } = map.on(('deleted') => console.log('Map deleted'));
// To remove the listener
off();
CopyCopied!
Use the LiveMap.off()
method to deregister a provided lifecycle event listener:
// Initial subscription
const listener = () => console.log('Map deleted');
map.on('deleted', listener);
// To remove the listener
map.off('deleted', listener);
CopyCopied!
Use the LiveMap.offAll()
method to deregister all lifecycle event listeners:
map.offAll();
CopyCopied!
Composability
A LiveMap
can store other LiveMap
or LiveCounter
objects as values for its keys, enabling you to build complex, hierarchical object structure. This enables you to represent complex data models in your applications while ensuring realtime synchronization across clients.
// Create a hierarchy of objects using LiveMap
const counter = await channel.objects.createCounter();
const map = await channel.objects.createMap({ nestedCounter: counter });
const outerMap = await channel.objects.createMap({ nestedMap: map });
await root.set('outerMap', outerMap);
// resulting structure:
// root (LiveMap)
// └── outerMap (LiveMap)
// └── nestedMap (LiveMap)
// └── nestedCounter (LiveCounter)
CopyCopied!