{"id":8755,"date":"2020-06-02T10:01:46","date_gmt":"2020-06-02T17:01:46","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=8755"},"modified":"2023-09-29T13:48:47","modified_gmt":"2023-09-29T20:48:47","slug":"store-sync-binary-data-attachments-blobs-couchbase-mobile","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/","title":{"rendered":"Handle Binary Data Attachments &amp; Blobs with Couchbase Mobile"},"content":{"rendered":"<p><a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.7\/cbmintro.html\">Couchbase Mobile<\/a> supports a JSON document style NoSQL data model. In addition to supporting the standard JSON data types, Couchbase Mobile also supports binary data that include images, audio, video, PDF files, etc. A JSON document can be associated with one or more elements of binary data referred to as \u201cattachments\u201d or \u201cblobs\u201d. The binary data can be synced between Couchbase Lite clients and the server via the Sync Gateway. In this post, we discuss how to create binary data attachments, how to retrieve and update them. We also take a look under the hood at how attachments are internally represented, related idiosyncrasies and how to deal with them.<\/p>\n<p>Everything in this post applies to a Couchbase Mobile 2.x based deployment.<\/p>\n<h2 id=\"background:attachmentsandblobs\">Background: Attachments and Blobs<\/h2>\n<p>Support for associating binary data with JSON documents within Couchbase Mobile has evolved over the years. The internal representation of binary data within the JSON document has changed across versions of Couchbase Mobile. In Couchbase Mobile 1.x, binary data was stored in the form of \u201cattachments\u201d within a top-level \u201c_<em>attachments<\/em>\u201d attribute. Couchbase Mobile introduced the <a href=\"https:\/\/docs.couchbase.com\/couchbase-lite\/2.7\/swift.html#blobs\">blob<\/a> data type for storing binary data. In most cases, the discrepancy between the representations across versions is seamlessly handled by Couchbase Mobile so end users don\u2019t have to do anything special within their apps to deal with it. However, there are certain cases wherein app developers would have to take extra measures to deal with the discrepancy. We will also discuss those measures in this post and try to address some commonly asked questions.<\/p>\n<h2 id=\"workflow1:handlingattachmentscreatedoncouchbaselite\">Workflow #1: Handling attachments created on Couchbase Lite<\/h2>\n<p>Let\u2019s take a look at how you can create JSON documents with binary data attachments with Couchbase Lite and sync them over to the server-side. This is the flow that we will be describing:<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2020\/05\/attachments.png\" alt=\"\" \/><\/figure>\n<h3 id=\"createbinarydataoncouchbaselite\">Create binary data attachments on Couchbase Lite<\/h3>\n<p>Developers must use the <a href=\"https:\/\/docs.couchbase.com\/couchbase-lite\/2.7\/swift.html#blobs\">blob API<\/a> for creating blob data. A document can be associated with one or more attachments or blobs. Here is a code snippet that shows the usage of this API in swift. Refer to the developer documentation for equivalent code snippets for other platforms.<\/p>\n<pre><code>\r\n let mutableDoc = MutableDocument.init(id: \"user::priya\")\r\n if let profileImage = UIImage(named: \"profile.jpg\"), let imageData = UIImageJPEGRepresentation(profileImage, 0.75) {\r\n   let blob = Blob(contentType: \"image\/jpeg\", data: imageData)\r\n   mutableDoc.setBlob(blob, forKey: \"image\")\r\n }\r\n \/\/ \u2026 Add other properties\r\n mutableDoc.setString(\"user\", forKey: \"type\")\r\n mutableDoc.setString(\"Priya\", forKey: \"name\")\r\n mutableDoc.setString(\"priya.rajagopal@couchbase.com, forKey: \"email\")\r\n do {\r\n   try? db.saveDocument(mutableDoc)\r\n }\r\n catch {\r\n   print(\"Error in saving document : (error)\")\r\n }\r\n<\/code><\/pre>\n<h3 id=\"internalrepresentation\">Internal Representation<\/h3>\n<p>When the document is created in Couchbase Lite, internally, it looks something like this:<\/p>\n<pre><code>{\r\n  \"email\": \"priya.rajagopal@couchbase.com\",\r\n  \"image\": {\r\n   \"length\": 3888349,\r\n   \"digest\": \"sha1\u20134xlj1AKFgLdzcD7a1pVChrVTJIc=\",\r\n   \"content_type\": \"image\/jpeg\",\r\n   \"@type\": \"blob\"\r\n  },\r\n \"type\": \"user\",\r\n \"name\": \"Priya\",\r\n \"id\": \"user::priya\",\r\n \"rev\": \"1\u20131c8502034001b333cc469fe8c4c39e112eedf8a3\"\r\n}<\/code><\/pre>\n<p>Notice the <em>\u201c@type\u201d: \u201cblob\u201d <\/em>type entry created for the image type data.<\/p>\n<p><strong>Note<\/strong> that there are several system-level metadata such as _<em>id<\/em> that are included in the document. For brevity, not all of it is shown in the example. Applications must never make any assumptions about the format and availability of system-level metadata and for that reason, apps must never access those attributes directly. Always use the metadata retrieval options such as <em>meta().id<\/em>.<\/p>\n<h3 id=\"syncingattachmentstosyncgateway\">Syncing attachments to Sync Gateway<\/h3>\n<p>Sync Gateway is backward compatible with Couchbase Mobile 1.x. This implies that the Sync Gateway needs to be capable of processing binary data using the 1.x _ <em>attachments<\/em> style representation as well as the 2.x <em>blob<\/em> type. That also implies that when the Couchbase Lite 2.x client pushes up data to the Sync Gateway it needs to send it in a format that is compatible with 1.x clients.<\/p>\n<p>For that reason, when Couchbase Lite syncs the document with the Sync Gateway, it adds the <strong><em>_<\/em><\/strong><em>attachments\u00a0<\/em>entry into the document. So the document when pushed up would look something like the example below. The list of attachments associated with the document is specified within the <em>_attachments<\/em> object.<\/p>\n<pre style=\"padding-left: 80px\"><em><code>{\r\n  \"attachments\": {\r\n  \"blob\/image\": {\r\n   \"content_type\": \"image\/jpeg\",\r\n   \"digest\": \"sha1\u20134xlj1AKFgLdzcD7a1pVChrVTJIc=\",\r\n   \"length\": 3888349,\r\n   \"revpos\": 1,\r\n   \"stub\": true\r\n   }\r\n  },\r\n  \"email\": \"priya.rajagopal@couchbase.com\",\r\n  \"image\": {\r\n  \"@type\": \"blob\",\r\n  \"content_type\": \"image\/jpeg\",\r\n  \"digest\": \"sha1\u20134xlj1AKFgLdzcD7a1pVChrVTJIc=\",\r\n  \"length\": 3888349\r\n  },\r\n  \"name\": \"Priya\",\r\n  \"type\": \"user\",\r\n  \"id\": \"user::priya\",\r\n  \"rev\": \"1\u20131c8502034001b333cc469fe8c4c39e112eedf8a3\",\r\n}<\/code><\/em><\/pre>\n<p><strong>Note<\/strong> that there are several system-level metadata such as _<em>id<\/em> that is included in the document. For brevity, not all of it is shown in the example. Applications must never make any assumptions about the format and availability of system-level metadata and for that reason, apps must never access those attributes directly. Always use the metadata retrieval options such as <em>meta().id<\/em>.<\/p>\n<h3 id=\"retrievalofattachmentonsyncgateway\">Retrieval of attachment on Sync Gateway<\/h3>\n<p>The attachment data must be retrieved through the Sync Gateway <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.7\/rest-api.html#\/attachment\/get__db___doc___attachment_\">_<em>attachments<\/em> REST<\/a> endpoint. At the time of writing of this post, attachments cannot be directly managed using the Couchbase Server SDKs.<\/p>\n<p>Here is a sample curl command to retrieve the attachment(s) associated with a document using the _<em>attachments<\/em> REST endpoint. You would replace the authorization header with suitable credentials corresponding to the user configured in your system. Also, notice the name of the attachment, &#8220;<em>blob_<\/em>%2Fimage&#8221; is the URL encoded version of <em>&#8220;blob<\/em>\/image&#8221;_.<\/p>\n<pre><code>curl -X GET \r\n 'https:\/\/sync-gateway-url:4984\/dbname\/user::priya\/blob_%2Fimage' \r\n -H 'Accept: application\/json' \r\n -H 'Authorization: Basic ZGVtbzpwYXNzd29yZA=='<\/code><\/pre>\n<h3 id=\"updatingattachmentsonsyncgateway\">Updating attachments on Sync Gateway<\/h3>\n<p>The attachment data must be updated through the Sync Gateway <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.7\/rest-api.html#\/attachment\/put__db___doc___attachment_\">_<em>attachments<\/em> REST<\/a> endpoint. At the time of writing of this post, mobile attachments cannot be managed using Couchbase Server SDKs.<\/p>\n<p>Here is a sample curl command to update an attachment associated with a document using the _<em>attachments<\/em> REST endpoint. You would replace the authorization header with suitable credentials corresponding to the user configured in your setup. Also, notice that the <em>\u201crev\u201d<\/em> parameter must be provided. This parameter corresponds to the revision of the document that is to be updated. You can retrieve the revId using the <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.7\/rest-api.html#\/document\/get__db___doc_\">GET document REST<\/a>.<\/p>\n<pre><code> curl -i -X PUT 'https:\/\/sync-gateway-url:4984\/dbname\/user::priya\/blob_%2Fimage?rev=12-fa2bf00dab7e811eb562a502429ec633' \r\n -H 'Accept: application\/json' \r\n -H 'Authorization: Basic ZGVtbzE6cGFzc3dvcmQ=' \r\n -H 'Content-Type: image\/png' \r\n -H 'cache-control: no-cache' \r\n \u2013data-binary \"@layered.png\"<\/code><\/pre>\n<h3 id=\"but...wait..amismatch\">But\u2026wait..a mismatch!<\/h3>\n<p>Now, after you update the attachment, if you retrieve the document using the <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.7\/rest-api.html#\/document\/get__db___doc_\">GET document REST<\/a>,<\/p>\n<pre><code> curl -X GET \r\n 'https:\/\/sync-gateway-url:4984\/dbname\/user::priya\/blob_%2Fimage' \r\n -H 'Accept: application\/json' \r\n -H 'Authorization: Basic ZGVtbzE6cGFzc3dvcmQ=' \r\n -H 'Content-Type: application\/json' \r\n -H 'cache-control: no-cache'<\/code><\/pre>\n<p>The corresponding response would look something like this:<\/p>\n<pre><code>{\r\n  \"attachments\": {\r\n  \"blob\/image\": {\r\n   \"content_type\": \"image\/png\",\r\n   \"digest\": \"sha1-XeeXt0I014+1qpH+s2S2AUSg4II=\",\r\n   \"length\": 3444504,\r\n   \"revpos\": 16,\r\n   \"stub\": true\r\n   }\r\n  },\r\n  \"id\": \"user::demo1\",\r\n  \"rev\": \"13-e61d1a9e63069030212007a8b5eddde9\",\r\n  \"address\": \"\",\r\n  \"email\": \"demo1\",\r\n  \"image\": {\r\n   \"@type\": \"blob\",\r\n   \"content_type\": \"image\/jpeg\",\r\n   \"digest\": \"sha1\u20134xlj1AKFgLdzcD7a1pVChrVTJIc=\",\r\n   \"length\": 3888349\r\n  },\r\n  \"name\": \"Priya Rajagopal\",\r\n  \"type\": \"user\"\r\n}<\/code><\/pre>\n<p>You will notice that the <em>_attachment<\/em> and <em>blob<\/em> entry do not match. While the <em>_attachment<\/em> entry points to the latest image, the <em>blob<\/em> entry still describes the old image. <em>But that is OK<\/em>!<\/p>\n<p>The reason for this discrepancy is because the Sync Gateway only deals with 1.x style attachments.<\/p>\n<p>So how does this still work?<\/p>\n<p>This works because within the context of the Sync Gateway which deals with 1.x style attachments, only the attachment entry is honored.<\/p>\n<p>But what about Couchbase Lite? What happens when the updated document is synced down by the Couchbase Lite 2.x client?<\/p>\n<p>When the document is replicated by Couchbase Lite 2.x client, Couchbase Lite looks for the presence of <em>_attachments<\/em> and <em>blobs<\/em> within the document and implements appropriate logic to identify that this was a 2.x style document that was created by a 2.x client but was subsequently updated by a 1.x client (such as the Sync Gateway REST API). It, therefore, treats the <em>_attachments<\/em> entry as the \u201creal\u201d attachment and unifies the corresponding blob entry.<\/p>\n<p>From a developer\u2019s perspective, all this is handled automatically. So you don\u2019t really have to worry about any of the details. As a developer, you would have to know how to retrieve the updated attachment from within Couchbase Lite enabled app.<\/p>\n<h3 id=\"retrievalofupdatedattachmentoncouchbaselite\">Retrieval of updated attachment on Couchbase Lite<\/h3>\n<p>When the updated attachment is synced over to your Couchbase Lite app, \u00a0use the <a href=\"https:\/\/docs.couchbase.com\/mobile\/2.7.0\/couchbase-lite-swift\/Classes\/Blob.html#\/s:18CouchbaseLiteSwift4BlobC11contentType4dataACSS_10Foundation4DataVtcfc\">Blob API<\/a> to retrieve the data. Here is a code snippet that shows the usage of this API in swift. Refer to the developer documentation for equivalent code snippets for other platforms.<\/p>\n<pre><code>\r\n if let doc = db.document(withID: \"user::priya\") {\r\n     let blobValue = doc.blob(forKey:\"image\")?.content\r\n     \/\/ use the blobValue\r\n }\r\n<\/code><\/pre>\n<p>Now let\u2019s look at the reverse flow.<\/p>\n<h2 id=\"workflow2:handlingofattachmentscreatedonsyncgateway\">Workflow #2: Handling of attachments created on Sync Gateway<\/h2>\n<p>Let\u2019s take a look at how you can create JSON documents with binary data attachments on Sync Gateway and sync it over to the Couchbase Lite side.<br \/>\nThis is the flow that we will be describing &#8211;<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2020\/05\/attachments-2.png\" alt=\"\" \/><\/figure>\n<h3 id=\"createbinarydataattachmentsonserver\">Create binary data attachments on Server<\/h3>\n<p>In order to attach binary data on the Couchbase Server side that can be synced over to the clients via the Sync Gateway, you would have to use the Sync Gateway <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.7\/rest-api.html#\/attachment\/put__db___doc___attachment_\">attachments REST endpoint<\/a>. At the time of writing of this post, mobile compatible attachments cannot be directly created using the Couchbase Server SDKs. The attachment data that is created through the Sync Gateway REST endpoint is persisted in the Couchbase Server bucket and synced over to Couchbase Lite clients subject to the access control policies configured on the Sync Gateway.<\/p>\n<p>In order to do this, first create a document (or retrieve a previously created document) and then create the attachment for the document. Alternatively, you could create a multi-part document with both JSON and binary data. But that could be tedious as you would need to also generate the relevant attachment metadata. So the steps outlined below is my preferred option<\/p>\n<ul>\n<li><strong>Create Document<\/strong><\/li>\n<\/ul>\n<p>A JSON document can be created directly on Couchbase Server using Couchbase Server SDK or the admin UI or you can create it using the <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.7\/rest-api.html#\/document\/put__db___doc_\">PUT Document<\/a> REST API. The document could have also been synced up from a Couchbase Lite client.<\/p>\n<p>Here is an example of using the Sync Gateway REST endpoint for creating a document with Id <em>\u201cuser::jane\u201d<\/em>. You would replace the authorization header with suitable credentials corresponding to the user configured in your setup.<\/p>\n<pre><code>curl -X PUT \r\n 'https:\/\/sync-gateway-url:4984\/dbname\/user::jane\/' \r\n -H 'Accept: application\/json' \r\n -H 'Authorization: Basic ZGVtbzpwYXNzd29yZA==' \r\n -H 'Content-Type: application\/json' \r\n -d '{\r\n \"email\": \"jane.doe@example.com\",\r\n \"type\": \"user\",\r\n \"name\": \"Jane Doe\"\r\n}'<\/code><\/pre>\n<p>The response would look something like below:<\/p>\n<pre><code>{\r\n  \"id\": \"user::jane\",\r\n  \"ok\": true,\r\n  \"rev\": \"1-ed2d37e7ece0dc5726fecd211433cbba\"\r\n}<\/code><\/pre>\n<ul>\n<li><strong>Create Attachment for Document on Sync Gateway<\/strong><\/li>\n<\/ul>\n<p>The attachment data must be created through the Sync Gateway <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.7\/rest-api.html#\/attachment\/put__db___doc___attachment_\">_<em>attachments<\/em> REST<\/a> endpoint. This step is identical to the previous flow when an attachment was being updated through the REST endpoint.<\/p>\n<p>Here is a sample curl command to update an attachment associated with a document using the _<em>attachments<\/em> REST endpoint. You would replace the authorization header with suitable credentials corresponding to the user configured in your setup. The <em>\u201crev\u201d<\/em> parameter must be provided. This parameter corresponds to the revision of the document that is to be updated.<\/p>\n<pre><code> curl -i -X PUT \r\n 'https:\/\/sync-gateway-url:4984\/dbname\/user::jane\/blob_%2Fimage?rev=1-ed2d37e7ece0dc5726fecd211433cbba' \r\n -H 'Accept: application\/json' \r\n -H 'Authorization: Basic ZGVtbzE6cGFzc3dvcmQ=' \r\n -H 'Content-Type: image\/png' \r\n \u2013data-binary \"@layered.png\u201d<\/code><\/pre>\n<h3 id=\"internalrepresentation\">Internal Representation<\/h3>\n<p>When the document is updated by the Sync Gateway, it would look something like this<br \/>\nIf you retrieve the document using the <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.7\/rest-api.html#\/document\/get__db___doc_\">GET document REST<\/a>,<\/p>\n<pre><code> curl -X GET \r\n 'https:\/\/sync-gateway-url:4984\/dbname\/user::jane\/blob_%2Fimage' \r\n -H 'Accept: application\/json' \r\n -H 'Authorization: Basic ZGVtbzE6cGFzc3dvcmQ=' \r\n -H 'Content-Type: application\/json' \r\n -H 'cache-control: no-cache'<\/code><\/pre>\n<p>The corresponding response would look something like this:<\/p>\n<pre><em><code>{\r\n  \"attachments\": {\r\n  \"blob\/image\": {\r\n   \"content_type\": \"image\/png\",\r\n   \"digest\": \"sha1-VteI8PPA3tFVxeW8z2qoJpQo40Y=\",\r\n   \"length\": 1768,\r\n   \"revpos\": 2,\r\n   \"stub\": true\r\n   }\r\n  },\r\n  \"id\": \"user::jane\",\r\n  \"rev\": \"2\u201395da324bd67db252d8b682cd113e3879\",\r\n  \"email\": \"jane.doe@example.com\",\r\n  \"type\": \"user\",\r\n  \"name\": \"Jane Doe\"\r\n}<\/code><\/em><\/pre>\n<p>Creating attachments using Sync Gateway\u2019s attachments REST API will result in the 1.x style representation of attachments. Notice that there is no 2.x style \u201cblob\u201d metadata. This is important to note when you access the document on Couchbase Lite<\/p>\n<h3 id=\"retrievalofupdatedattachmentoncouchbaselite\">Retrieval of updated attachment on Couchbase Lite<\/h3>\n<p>When the previously created document is synced over to the Couchbase Lite side, it detects that this is a 1.x style document and leaves the <em>_attachments<\/em>\u00a0entry intact. It treats objects nested within the <em>_attachments<\/em> entry as blobs. However, the document is not automatically updated to include \u201cblob\u201d entry that is added. So your app would need to look for the presence of blobs using the <a href=\"https:\/\/docs.couchbase.com\/mobile\/2.7.0\/couchbase-lite-swift\/Classes\/Blob.html#\/s:18CouchbaseLiteSwift4BlobC11contentType4dataACSS_10Foundation4DataVtcfc\">Blob API<\/a> in both locations.<\/p>\n<pre><code> \/\/ First look for blob at the top level blob entry\r\n if let imageVal = userVal.blob(forKey:\"image\")?.content {\r\n   \/\/ imageVal contains the attachment\r\n }\r\n else {\r\n   \/\/ Handle campatability with attachments created via Sync Gateway API\r\n   \/\/ Those attachments are created with 1.x style.\r\n   let attachments = userVal.dictionary(forKey: \"attachments\")\r\n   let imageVal = attachments?.blob(forKey:\"blob\/image\")?.content\r\n   \/\/ imageVal contains the attachment\r\n }<\/code><\/pre>\n<h2 id=\"faq\">FAQ<\/h2>\n<p>To wrap things up, I have compiled a list of commonly asked questions related to the handling of attachments in Couchbase Mobile<\/p>\n<h3 id=\"whereareattachmentsstored\">Where are attachments stored?<\/h3>\n<p>On Couchbase Lite, attachments are stored in the Couchbase Lite database instance that contains the corresponding document. It is stored separately from the document which contains the associated metadata that holds the reference to the attachment. If the same attachment is shared by multiple documents, only a single instance of the attachment is stored in the database.<\/p>\n<p>On Couchbase Server, attachments are stored in the same Couchbase Server bucket as the corresponding document. It is stored separately from the document which contains the associated metadata that holds the reference to the attachment. If the same attachment is shared by multiple documents, only a single instance of the attachment is stored in the bucket.<\/p>\n<h3 id=\"howmanyattachmentscanbeassociatedwithadocument\">Is there a limit on the number of attachments that can be associated with a document?<\/h3>\n<p>You can attach one or more attachments to a JSON document. There are no hard limits on the number of attachments that can be associated with a document. However, since the attachment metadata is stored in the document xattrs (when shared_bucket_access is enabled) the number of attachments is bound by the allowed sync metadata size per document. With attachment metadata ranging from 100\u2013200 bytes and sync metadata size limit of 1MB per document, there are practical limits on the number of attachments that can be associated with a document.<\/p>\n<h3 id=\"whatisthemaximumsizeofanattachment\">What is the maximum size of an attachment?<\/h3>\n<p>The maximum size of each attachment is 20MB. This follows from the limits on document sizes on Couchbase Server. While Couchbase Lite itself allows attachments of size greater than 20MB and this is fine as long as the attachment is local-only and is guaranteed to never be synced to the server. However, developers are cautioned from creating such large attachments as they will be rejected by the Sync Gateway.<\/p>\n<h3 id=\"doattachmentssynceverytimetheassociatedjsondocumentchanges\">Do attachments sync every time the associated JSON document changes?<\/h3>\n<p>The replication protocol is optimized to only sync attachments when there are updates to them. This implies that they are not pushed or pulled by Couchbase Lite clients even if there are updates to other data in the associated JSON documents.<\/p>\n<h3 id=\"doattachmentssynceverytimetheassociatedjsondocumentchanges\">How does the protocol handle failures when syncing attachments?<\/h3>\n<p>The protocol is very robust in terms of handling sync failures for instance due to network disruptions. Documents are not persisted by the Sync Gateway or on Couchbase Lite until all associated attachments or blobs are successfully synced. So there could be a time window where you could end up with orphaned attachments\/blogs that have no associated documents. That&#8217;s not an issue because subsequent sync of the document will recognize that the attachment is already persisted and will not attempt to resynchronize it again.<\/p>\n<h2 id=\"whatsnext\">What\u2019s Next<\/h2>\n<p>Couchbase Mobile provides an easy-to-use interface to manage attachments. Check out the <a href=\"https:\/\/docs.couchbase.com\/couchbase-lite\/2.7\/swift.html#blobs\">documentation<\/a> for details on blob handling on each of the platforms.<br \/>\nIf you have questions or feedback, please leave a comment below or feel free to reach out to me via <a href=\"https:\/\/twitter.com\/rajagp\">Twitter<\/a>\u00a0or <a href=\"mailto:priya.rajagopal@couchbase.com\">email me<\/a>. The <a href=\"https:\/\/www.couchbase.com\/forums\/\">Couchbase dev forums<\/a> are a great place to engage with the Couchbase development community.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Couchbase Mobile supports a JSON document style NoSQL data model. In addition to supporting the standard JSON data types, Couchbase Mobile also supports binary data that include images, audio, video, PDF files, etc. A JSON document can be associated with [&hellip;]<\/p>\n","protected":false},"author":1423,"featured_media":10435,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[2370,1815,1810,1819,2366,2351],"tags":[2358],"ppma_author":[8948],"class_list":["post-8755","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-best-practices-and-tutorials","category-couchbase-mobile","category-data-modeling","category-sync-gateway","category-xamarin","tag-couchbase-mobile-2-x"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.7.1 (Yoast SEO v25.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Binary Data Attachments &amp; Blobs: Handle w\/ Couchbase Mobile<\/title>\n<meta name=\"description\" content=\"Create binary data attachments, retrieve and update them, and learn how attachments are internally represented, idiosyncrasies and dealing with them.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Handle Binary Data Attachments &amp; Blobs with Couchbase Mobile\" \/>\n<meta property=\"og:description\" content=\"Create binary data attachments, retrieve and update them, and learn how attachments are internally represented, idiosyncrasies and dealing with them.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2020-06-02T17:01:46+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-09-29T20:48:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2020\/06\/Blog-Binary-Data-1-1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1590\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Priya Rajagopal, Senior Director, Product Management\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@rajagp\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Priya Rajagopal, Senior Director, Product Management\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/\"},\"author\":{\"name\":\"Priya Rajagopal, Senior Director, Product Management\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c2da90e57717ee4970c48a87a131ac2c\"},\"headline\":\"Handle Binary Data Attachments &amp; Blobs with Couchbase Mobile\",\"datePublished\":\"2020-06-02T17:01:46+00:00\",\"dateModified\":\"2023-09-29T20:48:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/\"},\"wordCount\":2205,\"commentCount\":8,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/06\/Blog-Binary-Data-1-1.jpg\",\"keywords\":[\"couchbase mobile 2.x\"],\"articleSection\":[\"Android\",\"Best Practices and Tutorials\",\"Couchbase Mobile\",\"Data Modeling\",\"Sync Gateway\",\"Xamarin\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/\",\"name\":\"Binary Data Attachments & Blobs: Handle w\/ Couchbase Mobile\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/06\/Blog-Binary-Data-1-1.jpg\",\"datePublished\":\"2020-06-02T17:01:46+00:00\",\"dateModified\":\"2023-09-29T20:48:47+00:00\",\"description\":\"Create binary data attachments, retrieve and update them, and learn how attachments are internally represented, idiosyncrasies and dealing with them.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/06\/Blog-Binary-Data-1-1.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/06\/Blog-Binary-Data-1-1.jpg\",\"width\":1590,\"height\":628},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Handle Binary Data Attachments &amp; Blobs with Couchbase Mobile\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c2da90e57717ee4970c48a87a131ac2c\",\"name\":\"Priya Rajagopal, Senior Director, Product Management\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/4b50a54778b979d8c345b036ab138734\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/acfb2349788955262cd069497a9e7bdb0e97c26326f2e55811e7c1174e9ef1be?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/acfb2349788955262cd069497a9e7bdb0e97c26326f2e55811e7c1174e9ef1be?s=96&d=mm&r=g\",\"caption\":\"Priya Rajagopal, Senior Director, Product Management\"},\"description\":\"Priya Rajagopal is a Senior Director of Product Management at Couchbase responsible for developer platforms for the cloud and the edge. She has been professionally developing software for over 20 years in several technical and product leadership positions, with 10+ years focused on mobile technologies. As a TISPAN IPTV standards delegate, she was a key contributor to the IPTV standards specifications. She has 22 patents in the areas of networking and platform security.\",\"sameAs\":[\"https:\/\/x.com\/rajagp\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/priya-rajagopalcouchbase-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Binary Data Attachments & Blobs: Handle w\/ Couchbase Mobile","description":"Create binary data attachments, retrieve and update them, and learn how attachments are internally represented, idiosyncrasies and dealing with them.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/","og_locale":"en_US","og_type":"article","og_title":"Handle Binary Data Attachments &amp; Blobs with Couchbase Mobile","og_description":"Create binary data attachments, retrieve and update them, and learn how attachments are internally represented, idiosyncrasies and dealing with them.","og_url":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/","og_site_name":"The Couchbase Blog","article_published_time":"2020-06-02T17:01:46+00:00","article_modified_time":"2023-09-29T20:48:47+00:00","og_image":[{"width":1590,"height":628,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2020\/06\/Blog-Binary-Data-1-1.jpg","type":"image\/jpeg"}],"author":"Priya Rajagopal, Senior Director, Product Management","twitter_card":"summary_large_image","twitter_creator":"@rajagp","twitter_misc":{"Written by":"Priya Rajagopal, Senior Director, Product Management","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/"},"author":{"name":"Priya Rajagopal, Senior Director, Product Management","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c2da90e57717ee4970c48a87a131ac2c"},"headline":"Handle Binary Data Attachments &amp; Blobs with Couchbase Mobile","datePublished":"2020-06-02T17:01:46+00:00","dateModified":"2023-09-29T20:48:47+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/"},"wordCount":2205,"commentCount":8,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/06\/Blog-Binary-Data-1-1.jpg","keywords":["couchbase mobile 2.x"],"articleSection":["Android","Best Practices and Tutorials","Couchbase Mobile","Data Modeling","Sync Gateway","Xamarin"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/","url":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/","name":"Binary Data Attachments & Blobs: Handle w\/ Couchbase Mobile","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/06\/Blog-Binary-Data-1-1.jpg","datePublished":"2020-06-02T17:01:46+00:00","dateModified":"2023-09-29T20:48:47+00:00","description":"Create binary data attachments, retrieve and update them, and learn how attachments are internally represented, idiosyncrasies and dealing with them.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/06\/Blog-Binary-Data-1-1.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/06\/Blog-Binary-Data-1-1.jpg","width":1590,"height":628},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/store-sync-binary-data-attachments-blobs-couchbase-mobile\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Handle Binary Data Attachments &amp; Blobs with Couchbase Mobile"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c2da90e57717ee4970c48a87a131ac2c","name":"Priya Rajagopal, Senior Director, Product Management","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/4b50a54778b979d8c345b036ab138734","url":"https:\/\/secure.gravatar.com\/avatar\/acfb2349788955262cd069497a9e7bdb0e97c26326f2e55811e7c1174e9ef1be?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/acfb2349788955262cd069497a9e7bdb0e97c26326f2e55811e7c1174e9ef1be?s=96&d=mm&r=g","caption":"Priya Rajagopal, Senior Director, Product Management"},"description":"Priya Rajagopal is a Senior Director of Product Management at Couchbase responsible for developer platforms for the cloud and the edge. She has been professionally developing software for over 20 years in several technical and product leadership positions, with 10+ years focused on mobile technologies. As a TISPAN IPTV standards delegate, she was a key contributor to the IPTV standards specifications. She has 22 patents in the areas of networking and platform security.","sameAs":["https:\/\/x.com\/rajagp"],"url":"https:\/\/www.couchbase.com\/blog\/author\/priya-rajagopalcouchbase-com\/"}]}},"authors":[{"term_id":8948,"user_id":1423,"is_guest":0,"slug":"priya-rajagopalcouchbase-com","display_name":"Priya Rajagopal, Senior Director, Product Management","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/acfb2349788955262cd069497a9e7bdb0e97c26326f2e55811e7c1174e9ef1be?s=96&d=mm&r=g","author_category":"","last_name":"Rajagopal, Senior Director, Product Management","first_name":"Priya","job_title":"","user_url":"","description":"Priya Rajagopal is a Senior Director of Product Management at Couchbase responsible for developer platforms for the cloud and the edge. She has been professionally developing software for over 20 years in several technical and product leadership positions, with 10+ years focused on mobile technologies. As a TISPAN IPTV standards delegate, she was a key contributor to the IPTV standards specifications. She has 22 patents in the areas of networking and platform security."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/8755","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/1423"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=8755"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/8755\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/10435"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=8755"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=8755"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=8755"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=8755"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}