-
Notifications
You must be signed in to change notification settings - Fork 72
Legacy Attachment Handling
Couchbase Lite 2 changes the way attachments (now called "blobs") are represented in documents. They used to be stored in a top-level property named _attachments; now they can be stored anywhere in the document, in objects with a property "@type":"blob".
This causes some compatibility issues in several situations:
- Imported CBL 1.x databases containing attachments
- Replication with Sync Gateway (which currently does not know about the new schema)
- Documents replicated via Sync Gateway with other databases like CBL 1.x, CouchDB and PouchDB
Here's how we address this.
If a document contains an _attachments property whose value is an object (map/dictionary), any nested objects within that are considered to be blobs.
This rule needs to be honored by Couchbase Lite's sub-document API, as well as LiteCore code that detects attachments in documents (i.e. to set the internal kC4DocHasAttachment flag.)
Applications can choose to migrate attachments to blob properties if they wish, treating this like any other type of application schema change. They could upgrade every document (move attachments to blobs) at once when first opening the database, or wait until saving a document. In the latter case, their code (including queries!) needs to be flexible enough to look for blobs in either location.
When pushing a document that contains blobs to Sync Gateway:
- The LiteCore replicator will synthesize an
_attachmentsproperty in the JSON that it sends, containing an entry for each blob found in the document. (If this property already exists, the entries will be added to it.) - The name (key) of each attachment will be the dot-delimited JSON path of the blob, prefixed with a
$. - The blob will not be removed from its original location.
A CBL document that looks like this:
{ name: "Widget 124C41+",
photos: {
thumbnail: {
@type: "blob",
digest: "E3548AF60A3A407CA67389653ED82C09",
type: "image/jpeg",
length: 4321 }
}
} will be sent to Sync Gateway in this form:
{ name: "Widget 124C41+",
photos: {
thumbnail: {
@type: "blob",
digest: "E3548AF60A3A407CA67389653ED82C09",
type: "image/jpeg",
length: 4321 }
},
_attachments: {
"$.photos.thumbnail": {
digest: "E3548AF60A3A407CA67389653ED82C09",
type: "image/jpeg",
length: 4321 },
}
}(Note: For clarity I'm using JSON5 syntax here, i.e. omitting quotes around most keys.)
When pulling from Sync Gateway, every incoming document needs to be checked for an _attachments property. If it contains one, the replicator will do this:
- For each attachment in
_attachments:- Look through the document for a blob with a matching
digestvalue. - If found, remove the corresponding
_attachmentsentry.
- Look through the document for a blob with a matching
- If all
_attachmentsentries are removed, remove the property itself too.
If this is a document that was created by CBL 2, the result is that the synthesized _attachments property will be removed, and the document will be exactly as it was in the originating database.
Otherwise, (the document was created by CBL 1 or a different database), the _attachments property will be left alone since it contains the real attachments.
There are some other less likely cases, like a document upgraded from CBL 1.x where blobs have been added but the _attachments property not yet deleted; this algorithm should give good results then as well.