Ordering with Arrays
Using Y.Array to maintain element order in collaborative applications.
Overview
Y.Array provides ordered sequences that handle concurrent insertions gracefully. Combined with ID-based storage, Y.Array becomes the standard way to represent ordered collections.
The Pattern
Store only IDs in Y.Array; store content in Y.Map. See ID-Based Storage for the complete pattern and core operations.
Concurrent Insert Behavior
When two users insert at the same position simultaneously:
Initial: [A, B, C]
User 1 inserts X after A: [A, X, B, C]
User 2 inserts Y after A: [A, Y, B, C]
Merged: [A, X, Y, B, C] or [A, Y, X, B, C]The order of X and Y is determined by client IDs (arbitrary but consistent). Both items appear—neither is lost.
Grouped Ordering
For items grouped into categories, use a Map of Arrays:
items/ → Map<itemId, ItemData>
groupOrders/ → Map<groupId, Y.Array<itemId>>
├── 'todo' → ['k8d2fn3m', 'j7n3ks8w']
├── 'doing' → ['m4x9pt2q']
└── 'done' → ['p2r6vm4c', 'q5t8wn2x']Moving an item between groups: delete ID from source array, insert into target array, update item’s groupId field—all in one transaction.
Performance Tips
Large arrays (10,000+ items):
- Cache
order.toArray()instead of calling repeatedly - Use UI pagination/virtualization
Batch operations:
// WRONG: multiple syncs
for (const id of idsToRemove) {
order.delete(order.toArray().indexOf(id), 1)
}
// CORRECT: single transaction, delete from end first
yDoc.transact(() => {
const indices = idsToRemove
.map(id => order.toArray().indexOf(id))
.filter(i => i !== -1)
.sort((a, b) => b - a) // Descending
for (const i of indices) order.delete(i, 1)
})See Also
- ID-Based Storage - Content/order separation
- Transactions - Batching changes