This content is for SDK V4. For the latest version, see the V5 documentation.
This feature is available in SDK version 4.12.0 and later.
What Are Commit IDs?
Commit IDs are unique, monotonically increasing identifiers assigned to each data modification on your device:let result = try await ditto.store.execute(
query: "UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
)
print("Commit ID: \(result.commitID ?? -1)") // e.g., 1547
ditto.store.execute(
"UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
).use { result ->
println("Commit ID: ${result.commitId}") // e.g., 1547
}
const result = await ditto.store.execute(
"UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
);
console.log('Commit ID:', result.commitID); // e.g., 1547
import { Ditto, QueryResult } from '@dittolive/ditto'
const result: QueryResult = await ditto.store.execute(
"UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
)
const commitID: number | undefined = result.commitID
console.log('Commit ID:', commitID) // e.g., 1547
final result = await ditto.store.execute(
"UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
);
print("Commit ID: ${result.commitID}"); // e.g., 1547
try (DittoQueryResult result = ditto.store.execute(
"UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
)) {
System.out.println("Commit ID: " + result.getCommitId()); // e.g., 1547
}
using var result = await ditto.Store.ExecuteAsync(
"UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
);
Console.WriteLine($"Commit ID: {result.CommitID}"); // e.g., 1547
auto result = store.execute(
"UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
);
std::cout << "Commit ID: " << result.commitID() << std::endl; // e.g., 1547
let result = ditto.store().execute_v2((
"UPDATE products SET price = 99.99 WHERE _id = 'product-123'",
serde_json::Value::Null
)).await?;
println!("Commit ID: {:?}", result.commit_id()); // e.g., Some(1547)
result, err := dit.Store().Execute(
"UPDATE products SET price = 99.99 WHERE _id = 'product-123'")
if err != nil {
return err
}
defer result.Close() // cleanup
if commitID, ok := result.CommitID(); ok {
fmt.Printf("Commit ID: %s\n", commitID) // e.g. 1547
}
Key Properties
- Monotonic - Always increasing (1547, 1548, 1549β¦)
- Device-specific - Each device has its own sequence
- Per-operation - Every INSERT, UPDATE, DELETE gets a new ID
- Trackable - Use with
system:data_sync_infoto monitor sync progress
Tracking Sync Progress
Compare your commit ID withsynced_up_to_local_commit_id to see if peers have received your commit:
// Step 1: Execute statement and get commit ID
let result = try await ditto.store.execute(
query: "UPDATE orders SET status = 'shipped' WHERE _id = :id",
arguments: ["id": "order-456"]
)
let commitId = result.commitID!
// Step 2: Check if it synced to cloud
let syncResult = try await ditto.store.execute(
query: "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
)
if let item = syncResult.items.first,
let documents = item.value["documents"] as? [String: Any],
let syncedUpTo = documents["synced_up_to_local_commit_id"] as? Int64 {
if syncedUpTo >= commitId {
print("Commit synced to cloud")
} else {
print("Syncing...")
}
}
// Step 1: Execute statement and get commit ID
ditto.store.execute(
"UPDATE orders SET status = 'shipped' WHERE _id = :id",
mapOf("id" to "order-456")
).use { result ->
val commitId = result.commitId!!
// Step 2: Check if it synced to cloud
ditto.store.execute(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
).use { syncResult ->
val item = syncResult.items.firstOrNull()
val documents = item?.value?.get("documents") as? Map<String, Any>
val syncedUpTo = documents?.get("synced_up_to_local_commit_id") as? Long ?: -1
if (syncedUpTo >= commitId.longValue()) {
println("Commit synced to cloud")
} else {
println("Syncing...")
}
}
}
// Step 1: Execute statement and get commit ID
const result = await ditto.store.execute(
"UPDATE orders SET status = 'shipped' WHERE _id = :id",
{ id: "order-456" }
);
const commitId = result.commitID;
// Step 2: Check if it synced to cloud
const syncResult = await ditto.store.execute(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
);
if (syncResult.items.length > 0) {
const syncedUpTo = syncResult.items[0].value.documents.synced_up_to_local_commit_id;
if (syncedUpTo >= commitId) {
console.log("Commit synced to cloud");
} else {
console.log("Syncing...");
}
}
import { Ditto, QueryResult } from '@dittolive/ditto'
interface SyncDocuments {
sync_session_status: string
synced_up_to_local_commit_id: number
last_update_received_time: number
}
interface PeerSyncInfo {
_id: string
is_ditto_server: boolean
documents: SyncDocuments
}
// Step 1: Execute statement and get commit ID
const result: QueryResult = await ditto.store.execute(
"UPDATE orders SET status = 'shipped' WHERE _id = :id",
{ id: "order-456" }
)
const commitId: number = result.commitID!
// Step 2: Check if it synced to cloud
const syncResult: QueryResult = await ditto.store.execute(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
)
if (syncResult.items.length > 0) {
const peer = syncResult.items[0].value as PeerSyncInfo
const syncedUpTo: number = peer.documents.synced_up_to_local_commit_id
if (syncedUpTo >= commitId) {
console.log("Commit synced to cloud")
} else {
console.log("Syncing...")
}
}
// Step 1: Execute statement and get commit ID
final result = await ditto.store.execute(
"UPDATE orders SET status = 'shipped' WHERE _id = :id",
{"id": "order-456"}
);
final commitId = result.commitID!;
// Step 2: Check if it synced to cloud
final syncResult = await ditto.store.execute(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
);
if (syncResult.items.isNotEmpty) {
final documents = syncResult.items[0].value["documents"] as Map<String, dynamic>;
final syncedUpTo = documents["synced_up_to_local_commit_id"] as int;
if (syncedUpTo >= commitId) {
print("Commit synced to cloud");
} else {
print("Syncing...");
}
}
// Step 1: Execute statement and get commit ID
try (DittoQueryResult result = ditto.store.execute(
"UPDATE orders SET status = 'shipped' WHERE _id = :id",
Collections.singletonMap("id", "order-456")
)) {
long commitId = result.getCommitId();
// Step 2: Check if it synced to cloud
try (DittoQueryResult syncResult = ditto.store.execute(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
)) {
if (!syncResult.getItems().isEmpty()) {
Map<String, Object> value = syncResult.getItems().get(0).getValue();
Map<String, Object> documents = (Map<String, Object>) value.get("documents");
long syncedUpTo = (Long) documents.get("synced_up_to_local_commit_id");
if (syncedUpTo >= commitId) {
System.out.println("Commit synced to cloud");
} else {
System.out.println("Syncing...");
}
}
}
}
// Step 1: Execute statement and get commit ID
using var result = await ditto.Store.ExecuteAsync(
"UPDATE orders SET status = 'shipped' WHERE _id = :id",
new Dictionary<string, object> { { "id", "order-456" } }
);
var commitId = result.CommitID;
// Step 2: Check if it synced to cloud
using var syncResult = await ditto.Store.ExecuteAsync(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
);
if (syncResult.Items.Count > 0) {
var value = (Dictionary<string, object>)syncResult.Items[0].Value;
var documents = (Dictionary<string, object>)value["documents"];
var syncedUpTo = (long)documents["synced_up_to_local_commit_id"];
if (syncedUpTo >= commitId) {
Console.WriteLine("Commit synced to cloud");
} else {
Console.WriteLine("Syncing...");
}
}
// Step 1: Execute statement and get commit ID
auto result = store.execute(
"UPDATE orders SET status = 'shipped' WHERE _id = :id",
{{"id", "order-456"}}
);
auto commitId = result.commitID();
// Step 2: Check if it synced to cloud
auto syncResult = store.execute(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
);
if (!syncResult.items().empty()) {
const auto& value = syncResult.items()[0].value();
const auto& documents = value.at("documents").get<std::map<std::string, std::any>>();
auto syncedUpTo = std::any_cast<int64_t>(documents.at("synced_up_to_local_commit_id"));
if (syncedUpTo >= commitId) {
std::cout << "Commit synced to cloud" << std::endl;
} else {
std::cout << "Syncing..." << std::endl;
}
}
// Step 1: Execute statement and get commit ID
let result = ditto.store().execute_v2((
"UPDATE orders SET status = 'shipped' WHERE _id = :id",
serde_json::json!({"id": "order-456"})
)).await?;
let commit_id = result.commit_id().unwrap();
// Step 2: Check if it synced to cloud
let sync_result = ditto.store().execute_v2((
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
serde_json::Value::Null
)).await?;
if let Some(item) = sync_result.items().first() {
if let Some(value) = item.value().as_object() {
if let Some(documents) = value.get("documents").and_then(|d| d.as_object()) {
if let Some(synced_up_to) = documents.get("synced_up_to_local_commit_id").and_then(|s| s.as_i64()) {
if synced_up_to >= commit_id as i64 {
println!("Commit synced to cloud");
} else {
println!("Syncing...");
}
}
}
}
}
// Step 1: Execute statement and get commit ID
result, err := dit.Store().Execute(
"UPDATE orders SET status = 'shipped' WHERE _id = :id",
ditto.QueryArguments{"id" : "order-456"})
if err != nil {
return err
}
defer result.Close() // cleanup
commitID, _ := result.CommitID()
// Step 2: Check if it synced to cloud
syncResult, err := dit.Store().Execute(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true")
if err != nil {
return err
}
if result.ItemCount() > 0 {
item := result.Item(0)
defer item.Close() // cleanup
if documents, ok := item.Value()["documents"].(map[string]any); ok; {
if syncedUpTo, ok := documents["synced_up_to_local_commit_id].(int64); ok {
if syncedUpTo > commitID {
fmt.Println("Commit synced to cloud")
} else {
fmt.Println("Syncing...)
}
}
}
}
Monitoring Multiple Commits
Observers on
system:data_sync_info result in the callback triggering every 500ms even when the result remains the same. This frequency can be
configured using the live_query_system_collection_refresh_interval system parameter.var pendingCommits: [Int64] = []
// Make several commits
let result1 = try await ditto.store.execute(
query: "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
)
if let commitId1 = result1.commitID {
pendingCommits.append(commitId1)
}
let result2 = try await ditto.store.execute(
query: "INSERT INTO orders DOCUMENTS (:order)",
arguments: ["order": ["_id": "order-789", "status": "pending"]]
)
if let commitId2 = result2.commitID {
pendingCommits.append(commitId2)
}
// Watch them sync
let observer = ditto.store.registerObserver(
query: "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
) { result in
guard let item = result.items.first,
let documents = item.value["documents"] as? [String: Any],
let syncedUpTo = documents["synced_up_to_local_commit_id"] as? Int64 else { return }
// Check which commits have synced
var syncedCount = 0
for commitId in pendingCommits {
if syncedUpTo >= commitId {
print("Commit \(commitId) synced")
syncedCount += 1
} else {
break
}
}
// Remove synced commits
if syncedCount > 0 {
pendingCommits.removeFirst(syncedCount)
print("\(pendingCommits.count) commits remaining")
}
}
val pendingCommits = mutableListOf<BigInteger>()
// Make several commits
ditto.store.execute(
"UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
).use { result1 ->
result1.commitId?.let { pendingCommits.add(it) }
}
ditto.store.execute(
"INSERT INTO orders DOCUMENTS (:order)",
mapOf("order" to mapOf("_id" to "order-789", "status" to "pending"))
).use { result2 ->
result2.commitId?.let { pendingCommits.add(it) }
}
// Watch them sync
ditto.store.registerObserver(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
) { queryResult ->
queryResult.use { result ->
val item = result.items.firstOrNull() ?: return@registerObserver
val documents = item.value["documents"] as? Map<String, Any> ?: return@registerObserver
val syncedUpTo = documents["synced_up_to_local_commit_id"] as? Long ?: return@registerObserver
// Check which commits have synced
var syncedCount = 0
for (commitId in pendingCommits) {
if (syncedUpTo >= commitId.longValue()) {
println("β
Commit $commitId synced")
syncedCount++
} else {
break
}
}
// Remove synced commits
if (syncedCount > 0) {
repeat(syncedCount) { pendingCommits.removeAt(0) }
println("${pendingCommits.size} commits remaining")
}
}
}
const pendingCommits = [];
// Make several commits
const result1 = await ditto.store.execute(
"UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
);
pendingCommits.push(result1.commitID);
const result2 = await ditto.store.execute(
"INSERT INTO orders DOCUMENTS (:order)",
{ order: { _id: "order-789", status: "pending" } }
);
pendingCommits.push(result2.commitID);
// Watch them sync
const observer = ditto.store.registerObserver(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
(result) => {
if (!result.items.length) return;
const syncedUpTo = result.items[0].value.documents.synced_up_to_local_commit_id;
// Check which commits have synced
let syncedCount = 0;
for (const commitId of pendingCommits) {
if (syncedUpTo >= commitId) {
console.log(`Commit ${commitId} synced`);
syncedCount++;
} else {
break;
}
}
// Remove synced commits
if (syncedCount > 0) {
pendingCommits.splice(0, syncedCount);
console.log(`${pendingCommits.length} commits remaining`);
}
}
);
import { Ditto, QueryResult, StoreObserver } from '@dittolive/ditto'
interface SyncDocuments {
sync_session_status: string
synced_up_to_local_commit_id: number
last_update_received_time: number
}
interface PeerSyncInfo {
_id: string
is_ditto_server: boolean
documents: SyncDocuments
}
const pendingCommits: number[] = []
// Make several commits
const result1: QueryResult = await ditto.store.execute(
"UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
)
if (result1.commitID !== undefined) {
pendingCommits.push(result1.commitID)
}
const result2: QueryResult = await ditto.store.execute(
"INSERT INTO orders DOCUMENTS (:order)",
{ order: { _id: "order-789", status: "pending" } }
)
if (result2.commitID !== undefined) {
pendingCommits.push(result2.commitID)
}
// Watch them sync
const observer: StoreObserver = ditto.store.registerObserver(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
(result: QueryResult) => {
if (!result.items.length) return
const peer = result.items[0].value as PeerSyncInfo
const syncedUpTo: number = peer.documents.synced_up_to_local_commit_id
// Check which commits have synced
let syncedCount: number = 0
for (const commitId of pendingCommits) {
if (syncedUpTo >= commitId) {
console.log(`Commit ${commitId} synced`)
syncedCount++
} else {
break
}
}
// Remove synced commits
if (syncedCount > 0) {
pendingCommits.splice(0, syncedCount)
console.log(`${pendingCommits.length} commits remaining`)
}
}
)
final pendingCommits = <int>[];
// Make several commits
final result1 = await ditto.store.execute(
"UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
);
if (result1.commitID != null) {
pendingCommits.add(result1.commitID!);
}
final result2 = await ditto.store.execute(
"INSERT INTO orders DOCUMENTS (:order)",
{"order": {"_id": "order-789", "status": "pending"}}
);
if (result2.commitID != null) {
pendingCommits.add(result2.commitID!);
}
// Watch them sync
final observer = ditto.store.registerObserver(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
(result) {
if (result.items.isEmpty) return;
final documents = result.items[0].value["documents"] as Map<String, dynamic>;
final syncedUpTo = documents["synced_up_to_local_commit_id"] as int;
// Check which commits have synced
int syncedCount = 0;
for (final commitId in pendingCommits) {
if (syncedUpTo >= commitId) {
print("Commit $commitId synced");
syncedCount++;
} else {
break;
}
}
// Remove synced commits
if (syncedCount > 0) {
pendingCommits.removeRange(0, syncedCount);
print("${pendingCommits.length} commits remaining");
}
}
);
List<BigInteger> pendingCommits = new ArrayList<>();
// Make several commits
try (DittoQueryResult result1 = ditto.store.execute(
"UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
)){
if (result1.getCommitId() != null) {
pendingCommits.add(result1.getCommitId());
}
}
try (DittoQueryResult result2 = ditto.store.execute(
"INSERT INTO orders DOCUMENTS (:order)",
Collections.singletonMap("order", Map.of("_id", "order-789", "status", "pending"))
)){
if (result2.getCommitId() != null) {
pendingCommits.add(result2.getCommitId());
}
}
// Watch them sync
ditto.store.registerObserver(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
(result) -> {
try (result)
{
if (result.getItems().isEmpty()) return;
Map<String, Object> value = result.getItems().get(0).getValue();
Map<String, Object> documents = (Map<String, Object>) value.get("documents");
long syncedUpTo = (Long) documents.get("synced_up_to_local_commit_id");
// Check which commits have synced
int syncedCount = 0;
for (BigInteger commitId : pendingCommits) {
if (syncedUpTo >= commitId.longValue()) {
System.out.println("Commit " + commitId + " synced");
syncedCount++;
} else {
break;
}
}
// Remove synced commits
if (syncedCount > 0) {
pendingCommits.subList(0, syncedCount).clear();
System.out.println(pendingCommits.size() + " commits remaining");
}
}
}
);
var pendingCommits = new List<long>();
// Make several commits
using var result1 = await ditto.Store.ExecuteAsync(
"UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
);
if (result1.CommitID.HasValue) {
pendingCommits.Add(result1.CommitID.Value);
}
using var result2 = await ditto.Store.ExecuteAsync(
"INSERT INTO orders DOCUMENTS (:order)",
new Dictionary<string, object> {
{ "order", new Dictionary<string, object> {
{ "_id", "order-789" },
{ "status", "pending" }
}}
}
);
if (result2.CommitID.HasValue) {
pendingCommits.Add(result2.CommitID.Value);
}
// Watch them sync
var observer = ditto.Store.RegisterObserver(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
(result) => {
using (result)
{
if (result.Items.Count == 0) return;
var value = (Dictionary<string, object>)result.Items[0].Value;
var documents = (Dictionary<string, object>)value["documents"];
var syncedUpTo = (long)documents["synced_up_to_local_commit_id"];
// Check which commits have synced
int syncedCount = 0;
foreach (var commitId in pendingCommits) {
if (syncedUpTo >= commitId) {
Console.WriteLine($"Commit {commitId} synced");
syncedCount++;
} else {
break;
}
}
// Remove synced commits
if (syncedCount > 0) {
pendingCommits.RemoveRange(0, syncedCount);
Console.WriteLine($"{pendingCommits.Count} commits remaining");
}
}
}
);
std::vector<int64_t> pendingCommits;
// Make several commits
auto result1 = store.execute(
"UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
);
if (result1.commitID().has_value()) {
pendingCommits.push_back(result1.commitID().value());
}
auto result2 = store.execute(
"INSERT INTO orders DOCUMENTS (:order)",
{{"order", std::map<std::string, std::any>{
{"_id", std::string("order-789")},
{"status", std::string("pending")}
}}}
);
if (result2.commitID().has_value()) {
pendingCommits.push_back(result2.commitID().value());
}
// Watch them sync
auto observer = store.register_observer(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
[&pendingCommits](const auto& result) {
if (result.items().empty()) return;
const auto& value = result.items()[0].value();
const auto& documents = value.at("documents").get<std::map<std::string, std::any>>();
auto syncedUpTo = std::any_cast<int64_t>(documents.at("synced_up_to_local_commit_id"));
// Check which commits have synced
size_t syncedCount = 0;
for (const auto& commitId : pendingCommits) {
if (syncedUpTo >= commitId) {
std::cout << "Commit " << commitId << " synced" << std::endl;
syncedCount++;
} else {
break;
}
}
// Remove synced commits
if (syncedCount > 0) {
pendingCommits.erase(pendingCommits.begin(), pendingCommits.begin() + syncedCount);
std::cout << pendingCommits.size() << " commits remaining" << std::endl;
}
}
);
let mut pending_commits: Vec<u64> = Vec::new();
// Make several commits
let result1 = ditto.store().execute_v2((
"UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'",
serde_json::Value::Null
)).await?;
if let Some(commit_id) = result1.commit_id() {
pending_commits.push(commit_id);
}
let result2 = ditto.store().execute_v2((
"INSERT INTO orders DOCUMENTS (:order)",
serde_json::json!({"order": {"_id": "order-789", "status": "pending"}})
)).await?;
if let Some(commit_id) = result2.commit_id() {
pending_commits.push(commit_id);
}
// Watch them sync
let observer = ditto.store().register_observer(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
move |result| {
if result.items().is_empty() { return; }
if let Some(item) = result.items().first() {
if let Some(value) = item.value().as_object() {
if let Some(documents) = value.get("documents").and_then(|d| d.as_object()) {
if let Some(synced_up_to) = documents.get("synced_up_to_local_commit_id").and_then(|s| s.as_u64()) {
// Check which commits have synced
let mut synced_count = 0;
for &commit_id in &pending_commits {
if synced_up_to >= commit_id {
println!("Commit {} synced", commit_id);
synced_count += 1;
} else {
break;
}
}
// Remove synced commits
if synced_count > 0 {
pending_commits.drain(0..synced_count);
println!("{} commits remaining", pending_commits.len());
}
}
}
}
}
}
)?;
var pendingCommits []uint64
// Make several Commits
result1, err := dit.Store().Execute(
"UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"))
if err != nil {
return err
}
defer result1.Close() // cleanup
if commitID, ok := result1.CommitID(); ok {
pendingCommits = append(pendingCommits, commitID)
}
// Make several Commits
result2, err := dit.Store().Execute(
"INSERT INTO orders DOCUMENTS (:order)",
ditto.QueryArguments{"order" : ditto.Document{"_id" : "order-789", "status" : "pending}})
if err != nil {
return err
}
defer result2.Close() // cleanup
if commitID, ok := result2.CommitID(); ok {
pendingCommits = append(pendingCommits, commitID)
}
// Watch them sync
observer, err := dit.Store().RegisterObserver(
"SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
nil, // no query arguments
func(result *ditto.QueryResult) {
defer result.Close() // cleanup
if result.ItemCount() == 0 {
return
}
item := result.Item(0)
defer item.Close() // cleanup
if documents, ok := item.Value()["documents"].(map[string]any); ok {
if syncedUpTo, ok := documents["synced_up_to_local_commit_id"].(uint64); ok {
// Check which commits have synced
var syncedCount int
for _, commitID := range pendingCommits {
if syncedUpTo > commitID {
fmt.Printf("Commit %u synced\n", commitID)
syncedCount++
} else {
break
}
}
// Remove synced commits
if syncedCount > 0 {
pendingCommits = pendingCommits[syncedCount:]
fmt.Printf("%d commits remaining\n", len(pendingCommits))
}
}
}
}
)
if err != nil {
return err
}
Transaction Behavior
Commit IDs are only assigned after transactions complete:var queryResult: DittoQueryResult?
try await ditto.store.transaction { transaction in
queryResult = try await transaction.execute(
query: "INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
)
print(queryResult?.commitID ?? "nil") // nil - not committed yet
return try await transaction.commit()
}
print(queryResult?.commitID ?? "nil") // 1548 - now has commit ID
var queryResult: DittoQueryResult? = null
ditto.store.transaction { transaction ->
queryResult = transaction.execute(
"INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
)
println(queryResult?.commitId ?: "null") // null - not committed yet
transaction.commit()
}
queryResult.close()
println(queryResult?.commitId ?: "null") // 1548 - now has commit ID
let queryResult;
await ditto.store.transaction(async (transaction) => {
queryResult = await transaction.execute(
"INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
);
console.log(queryResult.commitID); // null - not committed yet
return transaction.commit();
});
console.log(queryResult.commitID); // 1548 - now has commit ID
import { Ditto, QueryResult } from '@dittolive/ditto'
let queryResult: QueryResult | undefined
await ditto.store.transaction(async (transaction) => {
queryResult = await transaction.execute(
"INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
)
console.log(queryResult.commitID) // undefined - not committed yet
return transaction.commit()
})
console.log(queryResult?.commitID) // 1548 - now has commit ID
late QueryResult queryResult;
await ditto.store.transaction((transaction) async {
queryResult = await transaction.execute(
"INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
);
print(queryResult.commitID); // null - not committed yet
return TransactionCompletionAction.commit;
});
print(queryResult.commitID); // 1548 - now has commit ID
DittoQueryResult queryResult = null;
ditto.store.transaction((transaction) -> {
queryResult = transaction.execute(
"INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
);
System.out.println(queryResult.getCommitId() != null ? queryResult.getCommitId() : "null"); // null - not committed yet
return transaction.commit();
});
queryResult.close();
System.out.println(queryResult.getCommitId() != null ? queryResult.getCommitId() : "null"); // 1548 - now has commit ID
DittoQueryResult queryResult = null;
await ditto.Store.TransactionAsync(async (transaction) => {
queryResult = await transaction.ExecuteAsync(
"INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
);
Console.WriteLine(queryResult.CommitID?.ToString() ?? "null"); // null - not committed yet
return await transaction.CommitAsync();
});
Console.WriteLine(queryResult.CommitID?.ToString() ?? "null"); // 1548 - now has commit ID
queryResult.Dispose();
std::optional<DittoQueryResult> queryResult;
ditto.get_store().transaction([&](auto& transaction) {
queryResult = transaction.execute(
"INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
);
std::cout << (queryResult->commitID().has_value() ?
std::to_string(queryResult->commitID().value()) : "null") << std::endl; // null - not committed yet
return transaction.commit();
});
std::cout << (queryResult->commitID().has_value() ?
std::to_string(queryResult->commitID().value()) : "null") << std::endl; // 1548 - now has commit ID
let mut query_result: Option<DittoQueryResult> = None;
ditto.store().transaction(|transaction| async move {
query_result = Some(transaction.execute_v2((
"INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })",
serde_json::Value::Null
)).await?);
println!("{:?}", query_result.as_ref().and_then(|r| r.commit_id())); // None - not committed yet
transaction.commit().await
}).await?;
println!("{:?}", query_result.as_ref().and_then(|r| r.commit_id())); // Some(1548) - now has commit ID
var queryResult *ditto.queryResult
_, err := dit.Store().Transaction(
nil, // default operations
func(transaction *ditto.Transaction) (ditto.TransactionCompletionAction, err) {
var err error
queryResult, err = transaction.Execute(
"INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })")
if err != nil {
return ditto.TransactionCompletionActionRollback, err
}
if commitID, ok := queryResult.CommitID(); ok {
// This branch won't be taken, as commit ID is not set yet
fmt.Printf("%d\n", commitID)
} else {
fmt.Println("No commit ID")
}
return ditto.TransactionCallbackActionCommit, nil
}
)
if err != nil {
return err
}
defer queryResult.Close() // cleanup
if commitID, ok := queryResult.CommitID(); ok {
// Now has commit ID
fmt.Printf("%d\n", commitID)
} else {
// This branch won't be taken
fmt.Println("No commit ID")
}
Checking Specific Peers
Track sync progress to any peer (not just cloud servers):// Check sync to a specific peer device
let syncResult = try await ditto.store.execute(
query: "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
)
if let item = syncResult.items.first,
let documents = item.value["documents"] as? [String: Any],
let peerSyncedUpTo = documents["synced_up_to_local_commit_id"] as? Int64 {
print("Peer has synced up to commit \(peerSyncedUpTo)")
}
// Check sync to a specific peer device
ditto.store.execute(
"SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
).use { syncResult ->
if (syncResult.items.isNotEmpty()) {
val item = syncResult.items.first()
val documents = item.value["documents"] as? Map<String, Any>
val peerSyncedUpTo = documents?.get("synced_up_to_local_commit_id") as? Long
println("Peer has synced up to commit $peerSyncedUpTo")
}
}
// Check sync to a specific peer device
const syncResult = await ditto.store.execute(
"SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
);
if (syncResult.items.length > 0) {
const peerSyncedUpTo = syncResult.items[0].value.documents.synced_up_to_local_commit_id;
console.log(`Peer has synced up to commit ${peerSyncedUpTo}`);
}
import { Ditto, QueryResult } from '@dittolive/ditto'
interface SyncDocuments {
sync_session_status: string
synced_up_to_local_commit_id: number
last_update_received_time: number
}
interface PeerSyncInfo {
_id: string
is_ditto_server: boolean
documents: SyncDocuments
}
// Check sync to a specific peer device
const syncResult: QueryResult = await ditto.store.execute(
"SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
)
if (syncResult.items.length > 0) {
const peer = syncResult.items[0].value as PeerSyncInfo
const peerSyncedUpTo: number = peer.documents.synced_up_to_local_commit_id
console.log(`Peer has synced up to commit ${peerSyncedUpTo}`)
}
// Check sync to a specific peer device
final syncResult = await ditto.store.execute(
"SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
);
if (syncResult.items.isNotEmpty) {
final documents = syncResult.items[0].value["documents"] as Map<String, dynamic>;
final peerSyncedUpTo = documents["synced_up_to_local_commit_id"] as int;
print("Peer has synced up to commit $peerSyncedUpTo");
}
// Check sync to a specific peer device
try (DittoQueryResult syncResult = ditto.store.execute(
"SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
)) {
if (!syncResult.getItems().isEmpty()) {
Map<String, Object> value = syncResult.getItems().get(0).getValue();
Map<String, Object> documents = (Map<String, Object>) value.get("documents");
long peerSyncedUpTo = (Long) documents.get("synced_up_to_local_commit_id");
System.out.println("Peer has synced up to commit " + peerSyncedUpTo);
}
}
// Check sync to a specific peer device
using var syncResult = await ditto.Store.ExecuteAsync(
"SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
);
if (syncResult.Items.Count > 0) {
var value = (Dictionary<string, object>)syncResult.Items[0].Value;
var documents = (Dictionary<string, object>)value["documents"];
var peerSyncedUpTo = (long)documents["synced_up_to_local_commit_id"];
Console.WriteLine($"Peer has synced up to commit {peerSyncedUpTo}");
}
// Check sync to a specific peer device
auto syncResult = store.execute(
"SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
);
if (!syncResult.items().empty()) {
const auto& value = syncResult.items()[0].value();
const auto& documents = value.at("documents").get<std::map<std::string, std::any>>();
auto peerSyncedUpTo = std::any_cast<int64_t>(documents.at("synced_up_to_local_commit_id"));
std::cout << "Peer has synced up to commit " << peerSyncedUpTo << std::endl;
}
// Check sync to a specific peer device
let sync_result = ditto.store().execute_v2((
"SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'",
serde_json::Value::Null
)).await?;
if let Some(item) = sync_result.items().first() {
if let Some(value) = item.value().as_object() {
if let Some(documents) = value.get("documents").and_then(|d| d.as_object()) {
if let Some(peer_synced_up_to) = documents.get("synced_up_to_local_commit_id").and_then(|s| s.as_u64()) {
println!("Peer has synced up to commit {}", peer_synced_up_to);
}
}
}
}
// Check sync to a specific peer device
syncResult, err := dit.Store().Execute(
"SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'")
if err != nil {
return err
}
defer syncResult.Close() // cleanup
if syncResult.ItemCount() > 0 {
item := syncResult.Item(0)
defer item.Close() // cleanup
if documents, ok := item.Value()["documents"].(map[string]any); ok {
if peerSyncedUpTo, ok := documents["synced_up_to_local_commit_id"].(uint64); ok {
fmt.Printf("Peer has synced up to commit %u\n", peerSyncedUpTo)
}
}
}
Best Practices
Remember that Ditto is offline-first. Use commit ID tracking to enhance user experience, not to block operations.
- Donβt block operations - Let users continue working while tracking sync in background
- Show progress indicators - Use commit tracking to display sync status in your UI
- Handle concurrency gracefully - Tracking should enhance the experience, not block it
- Monitor critical data - Focus tracking on important operations like payments or submissions
- Clean up tracking - Remove old commit IDs from your tracking lists to avoid memory issues
Related Topics
- Monitoring Sync Status - Overview of the system:data_sync_info collection
- Track Ditto Cloud Sync Status - Cloud-specific sync monitoring patterns