With Ditto SDK 4.11+, the new diffing APIs can be used with store observers to produce diffs between query results in consecutive invocations. This guide explains how to use the new diffing APIs to replace usage of the legacy live query APIs.
Overview
Live queries provide their callback with an event
parameter that contains a diff of the current live query event against the previous one—a summary of which documents in the result have been:
- Inserted: Indexes of new items
- Updated: Indexes of items that existed previously, but have changed
- Deleted: Indexes of items that were removed
- Moved: Pairs of indexes showing items that changed position
Store observers don’t have a built-in feature that provides a diff, as generating it is computationally expensive. However, you can use the new Differ
class to compute one when needed.
Key Differences
Legacy Live Query API
- Provides automatic diffing through the
event
parameter
- Maintains
event.oldDocuments
for deleted items (uses memory)
- Includes
event.isInitial
flag for the first callback
- Considers metadata changes as updates
Store Observer with Differ
- Requires manual diffing using the
Differ
class
- You must maintain previous results yourself
- No built-in initial event detection
- Ignores metadata-only changes when determining updates
Migration Example
Before: Using Legacy Live Query API
const appStateLegacy = {
inserted: null,
updated: null,
deleted: null
};
ditto.store
.collection('cars')
.findAll()
.observeLocal((documents, event) => {
if (event.isInitial) {
// Store all initial document IDs in app state
appStateLegacy.inserted = documents.map(doc => doc.value._id);
console.log("Initial live query event", appStateLegacy.inserted);
} else {
appStateLegacy.inserted = event.insertions?.map(
(index) => documents[index].value._id
);
appStateLegacy.updated = event.updates?.map(
(index) => documents[index].value._id
);
appStateLegacy.deleted = event.deletions?.map(
// accessing `event.oldDocuments`
(index) => event.oldDocuments[index].value._id
);
console.log("Live query event: ", JSON.stringify(appStateLegacy, null, 2));
}
});
After: Using Store Observer with Differ
import { Differ } from "@dittolive/ditto";
const differ = new Differ();
let previousItems; // like `event.oldDocuments`
let appStateDQL = {
inserted: null,
updated: null,
deleted: null
};
ditto.store.registerObserver('select * from cars', (result) => {
const diff = differ.diff(result.items);
appStateDQL.inserted = diff.insertions.map(
index => result.items[index].value._id
);
appStateDQL.updated = diff.updates.map(
index => result.items[index].value._id
);
appStateDQL.deleted = diff.deletions.map(
// accessing `previousItems`!
index => previousItems[index].value._id
);
if (!previousItems) {
console.log("Initial store observer callback", appStateDQL.inserted);
} else {
console.log("Store observer event", JSON.stringify(appStateDQL, null, 2));
}
previousItems = result.items;
});
Implementation Details
Handling Deleted and Moved Documents
With store observers, results from the previous event are no longer provided directly. You need to:
-
Store the current results at the end of each callback:
previousItems = result.items;
-
Use the indexes provided in diff.deletions
or diff.moves
to access deleted and moved documents from your stored previousItems
.
Detecting the Initial Event
The legacy API’s event.isInitial
flag isn’t available with the Differ. To detect the first callback:
if (!previousItems) {
// This is the initial callback
// All items will appear as insertions in the diff
}
In the first callback, all items passed to differ.diff
show up as insertions because the differ is initially empty.
The Differ
ignores metadata changes when determining updates. For example:
- Changing a document field and then setting it back to its original value will not be considered an update
- This differs from the legacy API which would count any change as an update
Interactive Example
Try the interactive example on CodePen to see both approaches in action. Open your browser console to observe the results.
Responses are generated using AI and may contain mistakes.