If I don’t have any Array or Text fields in my doc, is it actually possible to merge 2 docs with different histories? Bc Maps use LWW based on timestamps regardless?
const clientDoc = new Y.Doc()
clientDoc.getMap('m').set('x', 1)
clientDoc.getMap('m').set('x', 2)
// {x: 2}
const serverDoc = new Y.Doc()
serverDoc.getMap('m').set('x', 2)
// {x: 2}
clientDoc.getMap('m').set('x', 3)
// {x: 3}
// This doesn't work -- results in {x: 2}
// Y.applyUpdate(serverDoc, Y.encodeStateAsUpdate(clientDoc))
// This seems to work -- results in {x: 3}
const serverStateVector = Y.encodeStateVector(serverDoc)
const diff = Y.encodeStateAsUpdate(clientDoc, serverStateVector)
Y.applyUpdate(serverDoc, diff)
You can merge any two ydocs and will always end up with the same content on all peers. However, in most cases you won’t get the “intended” results. The merge is just random (one of the properties will overwrite the other one).
It would be better to diff and apply the differences, if you want to ensure that a certain set of changes “wins”.
~The merging won’t happen based on the timestamps in each doc?~ EDIT – Ah I see the timestamps are relative / only meaningful within a doc
The scenario I tried to illustrate above is where yjs docs are ephemeral + re-built periodically from a different serialization format in our DB. And I’m trying to figure out if we can ever merge client changes from the older doc with the server’s fresh doc.
What do you mean by diff and apply the differences? Is that different than what I had in the code snippet?
With respect to offline editing, merging changes from 2 docs with entirely different histories has the same limitations as merging 2 docs with a shared history that have since diverged?
const clientDoc = new Y.Doc()
clientDoc.getMap('m').set('x', 1)
clientDoc.getMap('m').set('x', 2)
const serverDoc = new Y.Doc()
// It actually doesn't matter which of these 2 ways serverDoc gets populated
// Y.applyUpdate(serverDoc, Y.encodeStateAsUpdate(clientDoc))
// serverDoc.getMap('m').set('x', 2)
clientDoc.getMap('m').set('x', 3) // op A
serverDoc.getMap('m').delete('x') // op B
// At this point, op A and op B are treated as concurrent so when merging the 2 docs,
// the conflict is randomly/arbitrarily resolved?