Introduction to CouchDB with .NET part 7: viewing changes made in the database
May 29, 2017 Leave a comment
Introduction
In the previous post we looked at batch insertions and updates in CouchDB. Batch operations are very useful if we intend to insert or update multiple documents at once. We can mix insertions, updates and deletions in the same batch operation. The individual modifications in the batch are treated in isolation. This implies that if one modification fails then it won’t affect the others. In other words batch operations are non-atomic in CouchDB.
In this post we’ll look at a way to check what changes have been made to a CouchDB database.
List of changes made to a database
The CouchDB HTTP API has a special endpoint /db-name/_changes to view the changes made to the selected database. E.g. to view the changes made to the persons database we would issue the following request:
GET http://localhost:5984/persons/_changes
The API responds with a list of changes sorted by date in an ascending order. Here’s what I got on my request:
{ "results": [{ "seq": "1-g1AAAAF1eJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rkQGPoiQFIJlkT1idA0hdPGF1CSB19QTV5bEASYYGIAVUOj8rgzmRMRcowG5qYWxgaGGMTR9B0xZATNtPjM0HIGrvE6P2AUQtyEdZAEzoeNA", "id": "3559d9c81c785b6bfc27a3490401b892", "changes": [{ "rev": "1-de9b80faccbc3bcd0dc04a8e2eee51a0" }] }, { "seq": "3-g1AAAAGXeJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rgzmRKRcowG5gZp5iYpSMTQMeY5IUgGSSPcikRAZ86hxA6uIJq0sAqasnqC6PBUgyNAApoNL5IF8wgn1hamFsYGhhTKIvIKYtgJi2nxibD0DU3idG7QOIWpCPsgCO2YLR", "id": "3559d9c81c785b6bfc27a34904019fa5", "changes": [{ "rev": "2-53da1176c8605ee7c21b7db5a1be0164" }] }, { "seq": "10-g1AAAAG5eJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rgzmRKRcowG5gZp5iYpSMTQMeY5IUgGSSPcikRAZ86hxA6uIJq0sAqasnqC6PBUgyNAApoNL5IF8wgn1hamFsYGhhTKIvIKYtgJi2nxibD0DU3gfZzA62OdnQ0sQgLYksmx9ATAP5OQsAStiNBg", "id": "3559d9c81c785b6bfc27a3490401af41", "changes": [{ "rev": "4-0ab70230331b8c0cb6b084e789795cae" }] }, { "seq": "14-g1AAAAHbeJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rgzmRKRcowG5gZp5iYpSMTQMeY5IUgGSSPdQkFrBJqSYWxkmmKaSa5AAyKR5kUiIDPnUJIHX1BNXlsQBJhgYgBVQ6H-Q6RrDrTC2MDQwtjEl0HcS0BRDT9hNj8wGI2vsgm9nBNicbWpoYpCWRZfMDiGkgP2cBAK34lz4", "id": "3559d9c81c785b6bfc27a3490401b00f", "changes": [{ "rev": "4-b191581a2cd889f62b696d3c0b549448" }] }, { "seq": "15-g1AAAAHbeJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rgzmRKRcowG5gZp5iYpSMTQMeY5IUgGSSPdQkFrBJqSYWxkmmKaSa5AAyKR5kUiIDPnUJIHX1BNXlsQBJhgYgBVQ6H-Q6RrDrTC2MDQwtjEl0HcS0BRDT9hNj8wGI2vsgmznANicbWpoYpCWRZfMDiGkgP2cBAK5Glz8", "id": "3559d9c81c785b6bfc27a349040177b0", "changes": [{ "rev": "4-05a41ea3b37ea0dea540fc34890c9369" }], "deleted": true }, { "seq": "18-g1AAAAH9eJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rgzmRKRcowG5gZp5iYpSMTQMeY5IUgGSSPdQkFrBJqSYWxkmmKaSa5AAyKR5kUiIDPnUJIHX1BNXlsQBJhgYgBVQ6H-Q6RrDrTC2MDQwtjEl0HcS0BRDT9hNj8wGI2vsgmznANicbWpoYpCWRZfMDiGngUGYGm5ZmmGyWaoDVtCwAWQahng", "id": "3559d9c81c785b6bfc27a34904018a42", "changes": [{ "rev": "3-af434f7f64b7304ae495bb58f05d1521" }], "deleted": true }, { "seq": "21-g1AAAAJTeJydz0sOgjAQBuAKJOLSE-gRWiilruQmSh-kEoSFstab6E30JnoTbCmJMSFE2MwkM5kv_xQAAF-5Aix5VXMlWFJUPC1UdToXeuWkgK2apsmVmzpHPZhDEgsc8L6DAYatdWXbTvJaSWIaskiMlRIj7ToJtBIhaYSRzrSoSyGzQynFkLA3wuVHgIzGRIo_hdLTFVx108jNKLNWiWgIEQ1HfmS1u9UeRnOtFlCCMjxJe1rtZTS_1TjaYJixSdrbas03W4Y4kbBXyz95mrk8", "id": "3559d9c81c785b6bfc27a3490401990e", "changes": [{ "rev": "3-03208d7c4416be70af857a2b8ab22fbe" }], "deleted": true }], "last_seq": "21-g1AAAAJTeJydz0sOgjAQBuAKJOLSE-gRWiilruQmSh-kEoSFstab6E30JnoTbCmJMSFE2MwkM5kv_xQAAF-5Aix5VXMlWFJUPC1UdToXeuWkgK2apsmVmzpHPZhDEgsc8L6DAYatdWXbTvJaSWIaskiMlRIj7ToJtBIhaYSRzrSoSyGzQynFkLA3wuVHgIzGRIo_hdLTFVx108jNKLNWiWgIEQ1HfmS1u9UeRnOtFlCCMjxJe1rtZTS_1TjaYJixSdrbas03W4Y4kbBXyz95mrk8", "pending": 0 }
That’s quite a long JSON but most of the space is take up by the “seq” property.
Here’s what the above JSON is telling us:
- results: the array of changes made to the documents in the database
- seq: each modification gets a unique sequence ID.
- id: the id of the document where the changes were made
- changes: an array of the revision numbers of the changes. The response will only contain the change with the most recent revision number for each document.
- deleted: only included if the document has been deleted
- last_seq: the sequence ID of the most recent modification. This can be useful if you’re planning to periodically check the changes since the previous time you called for the list of changes. We’ll see the filtering options later on.
- pending: the number of items remaining in the response feed
We can also retrieve the properties of the documents with the include_docs flag:
GET http://localhost:5984/persons/_changes?include_docs=true
The response will include a property called “doc” with the document details. Here’s an example:
"doc": { "_id": "3559d9c81c785b6bfc27a3490401b892", "_rev": "1-de9b80faccbc3bcd0dc04a8e2eee51a0", "first-name": "Freddie", "last-name": "Mercury", "age": 80 }
If you need to view the list of changes in the reverse order then attach the descending flag as follows:
http://localhost:5984/persons/_changes?descending=true
This will put the most recent change on top of the results array.
Limit the results
The “limit” and “since” query parameters help us reduce the size of the response. “since” is set to the sequence ID from which we want to view the list of changes. The “limit” is the number of changes we’d like to get from the sequence ID referenced in the “since” parameter. These two parameters can be used independently, i.e. the URL doesn’t need to include limit and since for the request to be valid. Here’s an example:
This will return 2 changes made after the sequence ID “10-g1AAA…” :
{ "results": [{ "seq": "14-g1AAAAHbeJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rgzmRKRcowG5gZp5iYpSMTQMeY5IUgGSSPdQkFrBJqSYWxkmmKaSa5AAyKR5kUiIDPnUJIHX1BNXlsQBJhgYgBVQ6H-Q6RrDrTC2MDQwtjEl0HcS0BRDT9hNj8wGI2vsgm9nBNicbWpoYpCWRZfMDiGkgP2cBAK34lz4", "id": "3559d9c81c785b6bfc27a3490401b00f", "changes": [{ "rev": "4-b191581a2cd889f62b696d3c0b549448" }] }, { "seq": "17-g1AAAAIxeJyd0EsOgjAQBuARSNClJ9AjtAIFV3IT7YtUgrBQ1noTvYneRG-CpWVjQlDcTJN2-v3TFgAwVa6AOa9qrgRLi4rTQlXHU6GPHAps0TRNrlzqHPSGj0gswhXvuzDAsKWubNNJnpFkmAQsEmOltJW2nQRGIoRGIdYzzepSyGxfSjEk7Frh_CEglsREih-F0tMVLnrRyLVVJkaJkgDhJBj5IqvdrHbPKXztfdjeZ5vsm2SO1yHK2F_JL6uZ33CNlmFOJOrV8jdEDa9j", "id": "3559d9c81c785b6bfc27a34904018a42", "changes": [{ "rev": "3-af434f7f64b7304ae495bb58f05d1521" }], "deleted": true }], "last_seq": "17-g1AAAAIxeJyd0EsOgjAQBuARSNClJ9AjtAIFV3IT7YtUgrBQ1noTvYneRG-CpWVjQlDcTJN2-v3TFgAwVa6AOa9qrgRLi4rTQlXHU6GPHAps0TRNrlzqHPSGj0gswhXvuzDAsKWubNNJnpFkmAQsEmOltJW2nQRGIoRGIdYzzepSyGxfSjEk7Frh_CEglsREih-F0tMVLnrRyLVVJkaJkgDhJBj5IqvdrHbPKXztfdjeZ5vsm2SO1yHK2F_JL6uZ33CNlmFOJOrV8jdEDa9j", "pending": 2 }
Filtering on document IDs
We can also get the changes for specific document IDs using a POST request:
POST http://localhost:5984/persons/_changes?filter=_doc_ids
I’ll include two document IDs in the request body:
{ "doc_ids": ["3559d9c81c785b6bfc27a34904019fa5", "3559d9c81c785b6bfc27a3490401af41" ] }
I now only get the most recent changes made to those two document IDs:
{ "results": [ { "seq": "2-g1AAAAF1eJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rgzmRKRcowG5gZp5iYpSMTQMeY5IUgGSSPcikRAZ86hxA6uIJq0sAqasnqC6PBUgyNAApoNL5xKhdAFG7nxi1ByBq7xOj9gFELci9WQDCI3kv", "id": "3559d9c81c785b6bfc27a34904019fa5", "changes": [ { "rev": "2-53da1176c8605ee7c21b7db5a1be0164" } ] }, { "seq": "10-g1AAAAHTeJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rgzmRKRcowG5gZp5iYpSMTQMeY5IUgGSSPcikRAZ86hxA6uKhNjKAbTQzSzQ1MQTayFmal5KalpmXmoLPhASQCfUEbcpjAZIMDUAKqHQ-yDZGsG2mFsYGhhbGJPoPYtoCiGn7ibH5AETtfZDN7GCbkw0tTQzSksiy-QHENJCfswAv35PO", "id": "3559d9c81c785b6bfc27a3490401af41", "changes": [ { "rev": "4-0ab70230331b8c0cb6b084e789795cae" } ] } ], "last_seq": "21-g1AAAAJTeJydz0sOgjAQBuAKJOLSE-gRWiilruQmSh-kEoSFstab6E30JnoTbCmJMSFE2MwkM5kv_xQAAF-5Aix5VXMlWFJUPC1UdToXeuWkgK2apsmVmzpHPZhDEgsc8L6DAYatdWXbTvJaSWIaskiMlRIj7ToJtBIhaYSRzrSoSyGzQynFkLA3wuVHgIzGRIo_hdLTFVx108jNKLNWiWgIEQ1HfmS1u9UeRnOtFlCCMjxJe1rtZTS_1TjaYJixSdrbas03W4Y4kbBXyz95mrk8", "pending": 0 }
Read the next post here.
You can view all posts related to data storage on this blog here.