> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/ably/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Operations

LiveObjects operations define how object data is updated and synchronized across multiple clients.

When you create or update an object, the change is expressed as an operation that is sent as an object message on the channel. The operation is then applied to the object instance on all clients that are subscribed to the channel.

This document explains the key concepts you need to know when working with operations.

## Operation types

Each object type supports specific operations that modify the object's data.

### LiveMap operations

[LiveMap](/docs/liveobjects/map) supports the following operations:

* `set`: Set a value for a key
* `remove`: Remove a key and its value

The value of an entry in a `LiveMap` instance can be a primitive type or a reference to another object.

```javascript theme={null}
await myObject.get('user').set('username', 'alice');
await myObject.get('user').remove('status');
```

### LiveCounter operations

[LiveCounter](/docs/liveobjects/counter) supports the following operations:

* `increment`: Increment the counter by a specified amount
* `decrement`: Decrement the counter by a specified amount

The amount is a double-precision floating-point number, which is the same as underlying type of a LiveCounter value.

<Aside data-type="note">
  The `decrement` operation is just syntactic sugar for `increment` with a negative amount.
</Aside>

```javascript theme={null}
await myObject.get('visits').increment(5);
await myObject.get('score').decrement(2);
```

### Create operations

Create operations are used to instantiate new objects of a given type.

Use `LiveMap.create()` and `LiveCounter.create()` to create new objects. These methods create special value types that can be assigned directly to paths:

```javascript theme={null}
// Create and assign a map with initial values
await myObject.set('user', LiveMap.create({
  username: 'alice',
  status: 'online'
}));

// Create and assign a counter with initial value
await myObject.set('score', LiveCounter.create(100));

// Create nested structures
await myObject.set('profile', LiveMap.create({
  name: 'Alice',
  score: LiveCounter.create(0),
  settings: LiveMap.create({
    theme: 'dark',
    notifications: true
  })
}));
```

When a create operation is processed, an object ID is automatically generated for the new object instance.

<Aside data-type="note">
  Objects created with `LiveMap.create()` and `LiveCounter.create()` are automatically reachable when you assign them to a path. You don't need to worry about orphaned objects unless you explicitly remove them from the tree and you have retained an `Instance` for the now-unreachable object.
</Aside>

## Object IDs

Every operation is expressed relative to a specific object instance, identified by its object ID, which determines which object the operation is applied to.

When using a `PathObject`, the specific object instance at the given path is evaluated at the time a method is called that updates the object. The client library will then publish an operation targeting the resolved object.

When using a client library object IDs are handled automatically, allowing you work directly with object references:

```javascript theme={null}
// The published operation targets the object ID of the object at 'user'
await myObject.get('user').set('username', 'alice');

// Get the specific instance and its ID
const userInstance = myObject.get('user').instance();
if (userInstance) {
  console.log('Object ID:', userInstance.id());
  await userInstance.set('username', 'alice');
}
```

## Batch operations

[Batch operations](/docs/liveobjects/batch-operations) can be used to batch a set of operations together:

* Multiple operations are grouped into a single atomic unit
* All operations in the batch either succeed together or fail together
* Operations in a batch are sent as a single message
* No operations from other clients can be interleaved within a batch

## Object message properties

Each operation is carried by an `ObjectMessage`, which is surfaced in subscriptions and provides metadata about the operation and who performed it.

### ObjectMessage

The following are the properties of an `ObjectMessage`:

| Property            | Description                                                                                                                       |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **id**              | Unique ID assigned by Ably to this object message                                                                                 |
| **clientId**        | The ID of the client that published this operation                                                                                |
| **connectionId**    | The ID of the connection used to publish this operation                                                                           |
| **timestamp**       | The timestamp of when the object message was received by Ably, as milliseconds since the Unix epoch                               |
| **channel**         | The name of the channel the object message was published to                                                                       |
| **operation**       | An `ObjectOperation` describing the operation that was applied                                                                    |
| **serial**          | An opaque string that uniquely identifies this object message                                                                     |
| **serialTimestamp** | A timestamp derived from the `serial` field                                                                                       |
| **siteCode**        | An opaque string that uniquely identifies the Ably site the object message was published to                                       |
| **extras**          | A JSON object of arbitrary key-value pairs that may contain metadata, and/or ancillary payloads. Valid payloads include `headers` |

### ObjectOperation

The `operation` field of an `ObjectMessage` contains an `ObjectOperation` with the following properties:

| Property      | Description                                                                                                                                                                                                                               |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **action**    | The operation action. One of: `'map.create'`, `'map.set'`, `'map.remove'`, `'counter.create'`, `'counter.inc'`, or `'object.delete'`                                                                                                      |
| **objectId**  | The ID of the object the operation was applied to                                                                                                                                                                                         |
| **mapOp**     | Present for map mutation operations (`'map.set'`, `'map.remove'`). Contains `key` (the key that was modified) and optionally `data` (an `ObjectData` representing the value assigned to the key, present only for `'map.set'` operations) |
| **counterOp** | Present for counter increment operations (`'counter.inc'`). Contains `amount` (the value added to the counter)                                                                                                                            |
| **map**       | Present for `'map.create'` operations. Defines the initial value of the map object with optional `semantics` (conflict-resolution strategy) and `entries` (initial key-value pairs)                                                       |
| **counter**   | Present for `'counter.create'` operations. Defines the initial value of the counter object with optional `count` (initial counter value)                                                                                                  |

#### ObjectData

The `data` field in `mapOp` is an `ObjectData` object that represents the value assigned to a map key. It has the following properties:

| Property     | Description                                                                                                                                        |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **objectId** | A reference to another object (such as a `LiveMap` or `LiveCounter`) by its object ID. Present when the value is a LiveObject                      |
| **value**    | A decoded primitive value (string, number, boolean, JSON-serializable object or array, or binary data). Present when the value is a primitive type |
