janl opened a new issue #1559: RFC: Sub-Document Operations URL: https://github.com/apache/couchdb/issues/1559 In regular CouchDB operation, clients have to provide a full document revision to be sent in order to make a document update. If only one or a few field values are to be updated, espcially on larger documents, the overhead of sending a full JSON body is significant. This proposal introduces CouchDB sub-document operations with the help of [JSON Pointer](https://github.com/janl/erl-jsonpointer) ([RFC 6901](http://tools.ietf.org/html/rfc6901))and [JSON Patch](http://jsonpatch.com) ([RFC 6902](http://tools.ietf.org/html/rfc6902)). JSON Pointer is designed to work inside a URI fragment (think `index.html#foo`), so it’d be great to get single-field oeprations handled that way. ## Single Field Updates Sample doc: ```json { "_id": "doc", "field": "hey there", "tags": ["zero", "one", "two"], "coordinates": { "lat": "123.456", "lon": "321.654" }, "age": 22 } ``` ### Example GET requests ``` GET /db/doc#field ``` Result: ``` "hey there" ``` * * * ``` GET /db/doc#coordinates ``` Result: ``` { "lat": "123.456", "lon": "321.654" } ``` * * * ``` GET /db/doc#coordinates/lat ``` Result: ``` "123.456" ``` * * * ``` GET /db/doc#age ``` Result: ``` 22 ``` * * * ``` GET /db/doc#tags/1 ``` Result: ``` "one" ``` ### Example PUT requests ``` PUT /db/doc?rev=$rev#field "hello there" ``` Result: ``` {"ok": true, "rev": "$rev2"} ``` New doc revision: ```json { "_id": "doc", "field": "hello there", "tags": ["zero", "one", "two"], "coordinates": { "lat": "123.456", "lon": "321.654" }, "age": 22 } ``` * * * ``` PUT /db/doc?rev=$rev#coordinates/updatedAt 1534321264 ``` Result: ``` {"ok": true, "rev": "$rev2"} ``` New doc revision: ```json { "_id": "doc", "field": "hello there", "tags": ["zero", "one", "two"], "coordinates": { "lat": "123.456", "lon": "321.654", "updatedAt": 1534321264 }, "age": 22 } ``` ### Example DELETE requests ``` DELETE /db/doc?rev=$rev#field ``` New doc revision: ```json { "_id": "doc", "tags": ["zero", "one", "two"], "coordinates": { "lat": "123.456", "lon": "321.654" }, "age": 22 } ``` ``` DELETE /db/doc?rev=$rev#tags/0 ``` New doc revision: ```json { "_id": "doc", "field": "hey there", "tags": ["one", "two"], "coordinates": { "lat": "123.456", "lon": "321.654" }, "age": 22 } ``` ## Multi Field Updates Of course, making multiple changes will be the next logical step. Thankfull JSON Patch provides a way to do this without having to go too much into canonical JSON serialisation required for a fully fledged diffing algorithm. ``` {POST,PATCH} /db/doc?rev=$rev Content-Type: application/json-patch+json [ { "op": "replace", "path": "/field", "value": "hello there"}, { "op": "replace", "path": "/age", "value": 23}, { "op": "add", "path": "/horse", "value": false} ] ``` New doc revision: ```json { "_id": "doc", "field": "hello there", "tags": ["zero", "one", "two"], "coordinates": { "lat": "123.456", "lon": "321.654" }, "age": 23, "horse": false } ``` ## Implementation Internally, CouchDB will still do the regular load, compare-revision, store procedure, it’s just that the new revision is now produced by applying a JSON Pointer or JSON Patch to the old revision of the doc, instead of being provided by the client. I’m happy to donate my JSON Pointer implementation, but any other will do, too, this is nice and minimal. For JSON Patch, there is an [MPL licensed library](https://github.com/marianoguerra/json-patch.erl) which might be problematic for LEGAL/LICENSING reasons, but the implementation doesn’t look too complicated to do from scratch. ## Notes I puntend on `Content-Type` defintions for single field operation because I couldn’t find proper precedent here. Strictly, JSON is always wrapped by an `{}`-object value, but we’re allowing to send the native JSON values like strings, numbers, booleans, arrays and objects, and only objects are strictly JSON themselves. I’d love some input here on my sparkling white bikeshed that desparately needs colour suggestions. I opted for keeping only explicit operations on collections, e.g. add value `x` to array in position `7`, and not “append `x` to {beginning,end} of array”. While the revision system should avoid any unexpected results here, it felt not quite right to allow relative operations. I might be able to be convinced otherwise :) There is also [JSON Merge Patch](https://tools.ietf.org/html/rfc7386) which is essentially sending fragments of changes that the recipient then has to apply as needed, which would work as well, but might be atiny bit more complicated to implement. If there is significant community interest, we can look into it.
---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: [email protected] With regards, Apache Git Services
