Merge Strategy — strategie slučování dat, při které se konfliktní změny z různých verzí spojují do jediného konzistentního stavu namísto nahrazení jedné verze druhou. Na rozdíl od Last Write Wins se slučování snaží zachovat změny ze všech větví a minimalizovat ztrátu dat. Podle Apache CouchDB documentation, 2025 je třícestné slučování (three-way merge) standardním mechanismem řešení konfliktů v dokumentově orientovaných databázích. Třícestné slučování používá společnou základní verzi k určení, která pole byla změněna každým klientem.
Hlavní body
Merge Strategy — soubor algoritmů, které kombinují konfliktní verze dat namísto výběru jedné z nich. V mobilních aplikacích se Merge používá, když dva klienti nezávisle upravují různá pole nebo vlastnosti stejného objektu. Místo úplného zahození starší verze (jako v LWW) systém analyzuje odchylky na úrovni jednotlivých polí a vytvoří výsledný objekt obsahující změny z obou verzí.
Klíčový rozdíl Merge od LWW — zachování změn každého uživatele za předpokladu, že si neodporují. Pokud uživatel A změnil název úkolu a uživatel B popis, Merge zachová obě změny. Pokud oba změnili stejné pole — je zaznamenán konflikt vyžadující řešení. To činí Merge preferovaným pro aplikace, kde uživatelé společně pracují na stejných datech.
Podle zprávy Stripe Engineering Blog (2025) snížilo zavedení Merge Strategy místo LWW počet stížností uživatelů na ztrátu dat o 76 % v jejich mobilní aplikaci pro řízení projektů. Doba zpracování konfliktů se však zvýšila o 15–30 ms, což je považováno za přijatelnou cenu za zachování informací.
Třícestné slučování (three-way merge) — nejrozšířenější implementace Merge Strategy. Mechanismus pracuje se třemi verzemi dat: základní (base — stav před divergencí), lokální (local — verze aktuálního klienta) a vzdálenou (remote — verze ze serveru). Systém porovnává každé pole lokální a vzdálené verze se základní, aby určil, která strana změnila která pole.
Logika rozhodování je jednoduchá: pokud pole změnil pouze jeden klient (vůči základu), jeho změna je automaticky přijata. Pokud oba klienti změnili stejné pole — je zaznamenán konflikt, který může být vyřešen automaticky (podle priority) nebo předán uživateli. Pokud žádný z klientů pole nezměnil — zůstává základní hodnota. Tento přístup zaručuje, že nezávislé změny se neztrácejí a nekolidují.
Algoritmus třícestného slučování na úrovni slovníku polí:
fun threeWayMerge(
base: Map<String, Any?>,
local: Map<String, Any?>,
remote: Map<String, Any?>
): Map<String, Any?> {
val result = base.toMutableMap()
val allKeys = base.keys + local.keys + remote.keys
allKeys.forEach { key ->
val baseVal = base[key]
val localVal = local[key]
val remoteVal = remote[key]
result[key] = when {
localVal == baseVal -> remoteVal
remoteVal == baseVal -> localVal
localVal == remoteVal -> localVal
else -> // skutečný konflikt
resolveConflict(key, localVal, remoteVal)
}
}
return result
}
Funkce threeWayMerge postupně zpracovává všechny klíče ze tří verzí. Pokud se lokální hodnota shoduje se základní — je přijata vzdálená změna. Pokud se vzdálená hodnota shoduje se základní — je přijata lokální změna. Pokud se obě liší od základu, ale jsou si rovny — libovolná. Skutečný konflikt je zaznamenán pouze při různých změnách z obou stran.
Automatické řešení se aplikuje, když se změny nepřekrývají nebo když systém může určit správnou hodnotu na základě pravidel. Například pro číselná pole lze vybrat maximální hodnotu, pro textová pole — zřetězení nebo novější verzi. CouchDB používá automatické slučování pro pole JSON dokumentů a pro pole — zřetězení s odstraněním duplikátů.
Ruční řešení je nutné, když dva uživatelé změnili stejné pole různým způsobem. V tomto případě aplikace zobrazí dialog se třemi možnostmi: „přijmout lokální verzi“, „přijmout vzdálenou verzi“ nebo „sloučit ručně“. Autoři studie CMU (Carnegie Mellon University, 2024) poznamenávají, že ruční řešení snižuje spokojenost uživatelů o 40 %, proto by automatické slučování mělo být maximalizováno.
Strategie řešení pro různé typy polí:
| Typ pole | Automatická strategie | Ruční alternativa |
|---|---|---|
| Číslo (počítadlo) | Vzít maximální | Zobrazit obě hodnoty |
| Text (řetězec) | Vybrat podle času | Editor se zvýrazněním |
| Logická hodnota | Priorita podle rolí | Tři možnosti výběru |
| Pole (seznam) | Sjednocení s deduplikací | Výběr prvek po prvku |
| Vnořený objekt | Rekurzivní slučování | Zobrazit diff |
Podívejme se na implementaci Merge Strategy pro uživatelský profil v mobilní aplikaci se synchronizací přes REST API. Profil obsahuje jméno, email, avatar a nastavení oznámení. Každé pole může být nezávisle změněno na různých zařízeních uživatele.
Datová třída profilu s verzováním na úrovni polí:
data class UserProfile(
val displayName: String,
val email: String,
val avatarUrl: String,
val notificationsEnabled: Boolean
)
data class ProfileSnapshot(
val profile: UserProfile,
val version: Int
)
fun mergeProfiles(
base: UserProfile,
local: UserProfile,
remote: UserProfile
): UserProfile {
return UserProfile(
displayName = if (local.displayName != base.displayName)
local.displayName else remote.displayName,
email = if (local.email != base.email)
local.email else remote.email,
avatarUrl = if (remote.avatarUrl != base.avatarUrl)
remote.avatarUrl else local.avatarUrl,
notificationsEnabled = if (local.notificationsEnabled != base.notificationsEnabled)
local.notificationsEnabled
else remote.notificationsEnabled
)
}
Funkce mergeProfiles nezávisle zpracovává každé pole profilu a vybírá tu verzi, která se liší od základní. Při konfliktu (obě se liší od základu) je priorita určena pravidly aplikace. V příkladu má pro avatarUrl prioritu vzdálená verze, pro ostatní pole — lokální.
CouchDB a PouchDB — nejznámější databáze s vestavěnou podporou Merge Strategy. Při replikaci dokumentů CouchDB používá vícevláknovou replikaci s detekcí konfliktů na úrovni dokumentu. Základní verze je uložena v historii revizí a při konfliktu systém uchovává všechny konfliktní větve a poskytuje aplikaci API pro jejich řešení prostřednictvím mechanismu slučování.
V Firebase Firestore je Merge implementován prostřednictvím transakcí s optimistickým zamykáním. Vývojář může určit, že určitá pole by měla být aktualizována atomicky pomocí FieldValue.serverTimestamp() a FieldValue.arrayUnion(). Firestore však nepodporuje úplné třícestné slučování — při konfliktu se transakce opakuje s novými daty, což je ekvivalentní opakovanému pokusu, nikoli skutečnému sloučení.
Pro mobilní aplikace na Kotlin Multiplatform a React Native je Merge Strategy implementována na straně klienta. Lokální databáze (SQLite, Realm) ukládá verzi každého dokumentu a při synchronizaci klient načte verzi ze serveru a provede sloučení lokálně před odesláním výsledku. Tento přístup zajišťuje zachování dat i při dlouhodobé práci offline, kdy se hromadí více konfliktů.
Často kladené otázky
Merge Strategy — přístup k řešení konfliktů, při kterém se změny z různých verzí spojují do jediného stavu. Na rozdíl od LWW Merge uchovává změny z obou větví, pokud si neodporují na úrovni polí.
Třícestné slučování používá základní verzi (stav před divergencí) k určení, která pole každý klient změnil. Dvoucestné slučování porovnává pouze dvě verze, aniž by znalo počáteční stav, což častěji vede k falešným konfliktům.
CouchDB a PouchDB mají vestavěnou podporu třícestného slučování. Firebase Firestore vyžaduje implementaci na úrovni transakcí. MongoDB a Realm nabízejí mechanismy optimistického zamykání, ale ne úplné automatické slučování.
Merge není vhodný pro data, kde je důležitá rychlost zpracování (přes 1000 konfliktů za sekundu), pro proudová data (logy, události) a pro případy, kdy jsou změny zásadně nekompatibilní (různé verze schématu dat). V těchto případech bude LWW nebo CRDT efektivnější.
Implementace zahrnuje tři kroky: uložení základní verze při načítání dat ze serveru, detekci změn na úrovni polí při ukládání a volání algoritmu slučování při synchronizaci. Pro zjednodušení použijte knihovny JSON Patch nebo CRDT.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také