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

Reply via email to