Sub document update for a nested array document

java

#1

Is it possible (If so how?) to use mutateIn and update only a fragment at apps level, so that it adds/updates the entire fragment of apps but only for “arraySubOptions2” alone, and it shouldn’t remove arraySubOptions1? I have pasted the fragment and the entire structure below?

Sample structure:

Fragment to be updated:


#2

If i use the mutateIn option, it is treating the fragment as a string, and replaces the structure with quoted escaped String.
If I send the JsonObject as the fragment to be updated,

I get “BinaryResponse{bucket=‘bucketName’, status=INVALID_ARGUMENTS (4), request=SubDictUpsertRequest{observable=rx.subjects.AsyncSubject@147bcbe1, bucket=‘bucketName’}, content=EmptyByteBufBE}”


Does Couchbase partial JSON update?
#3

I believe what you’re asking for it a “sub-document merge” operation - i.e. you want to merge some of the existing content with your new value.

The current Sub-Document API doesn’t support that - it will always operate on specific path(s), and all of that path(s). For example, you could perform a mutateIn on apps[0].enrollList[0].arrayOptions[0] if you wished, but that wouldn’t affect any other elements.

You may be able to restructure your documents - note you can access up to 16 paths inside a document in a single sub-document operation.

(As an aside, your current document structure isn’t best suited for sub-document access. It would probably be better if arrayOptions was actually a dictionary; with arraySubOptions1 and 2 as dictionary keys - that would allow direct access to arraySubOptions1 without having to know which array index it was under).


#4

thanks for your response @drigby, will have to trunk that through…
I just read under Update array of object if object exist else insert new object
so I should atleast be able to replace the specific enrollList element based on a condition within the deviceInfo object field?

trying to see if that would help at the most? Would the 16 paths (update) limit apply if i replace a specific index of array field enrollList based on a condition?


#5

I think there’s maybe some confusion about the different APIs available to you:

  • Using the Sub-Document API, you can access up to 16 paths inside a single document. There’s no predicate support; you simply specify the path you wish to write and the value to with to add.
  • Using N1QL, you can create very complex queries (including predicates) across multiple documents.

The Sub-Document API is essentially an extension of the original KV API - you still access a single document (one key), but you can access only part of the value. N1QL on the other hand is an SQL-like query language which allows much more complicated requests, at the cost of (typically) being slower than the Sub-Document API.


#6

@drigby
thanks for your inputs, but I’m having such trouble with updates to specific array index, and I could not find an example depicting this. (all the examples depict, the vanilla flavor, updates to specific fields and not a collection)
I have been trying the n1ql option, and the subdocument mutateIn operation.

Subdocument: (this isn’t doing the update at enrollInfo[x] index level as yet, as I’m unable to figure out that part)
mybucket.mutateIn(“documentIdValue”).upsert(“apps[0]”, jsonDocument.content(), subdocOptionsBuilder).execute();

where jsonDocument.content() is the JsonDocument_having the enrollList structure,
getting the error below:
“BinaryResponse{bucket=‘myBucket’, status=INVALID_ARGUMENTS (4), request=SubDictUpsertRequest{observable=rx.subjects.AsyncSubject@5b7e6593, bucket=‘myBucket’}, content=EmptyByteBufBE}”

I dont think subdocument mutateIn helps my case, as the update has to be based on the field value of the specific array Index I’m trying to update.

N1QL:
myBucket.query(N1qlQuery.simple(“UPDATE myBucket AS mBucket USE KEYS ‘documentId’ SET enroll = ARRAY_DISTINCT( ARRAY_APPEND( ARRAY CASE WHEN enroll.deviceInfo.id = ‘testing1’ THEN ‘arrayJsonStructure’ ELSE enroll END, ‘arrayJsonStructure’) ) FOR enroll IN app.enrollList, app IN myBucket.apps END”))

fatal error

I think the N1QL query will help, but not sure how to get subdocument set to the enroll object.

note: I’m using the java client 2.4.5