Subdocument upsert / insert

I have the below object inside couchbase document.

{
‘dict’: {
‘nestedDict’: {
‘value1’: 123,
‘value2’: 456,
‘value3’: 789
},

}

And I have map object as shown below

“value4”, 987
“value5”, 654

I need to update the couchbase document. Using upsert or insert is there is a way to update so that I get the following saved inside the couchbase.

{
‘dict’: {
‘nestedDict’: {
‘value1’: 123,
‘value2’: 456,
‘value3’: 789,
‘value4’: 987,
‘value5’: 654
},

}

I tried with insert and upsert

bucket…mutateIn(id).upsert(“dict.nestedDict”, getMap(), new SubdocOptionsBuilder().createPath(true)).execute();

But I get below. Just curious whether is there is way to preserve subdocuments that are not matching with the map object. Basically only the map object should
be inserted or updated based on on the map key.

{
‘dict’: {
‘nestedDict’: {
‘value4’: 987,
‘value5’: 654
},

}
CC: @vsr1 @graham.pople

Thanks

If you want to use N1QL

UPDATE mybucket AS b  USE KEYS "key1"
SET b.dict.nestedDict = OBJECT_CONCAT(b.dict.nestedDict, {"value4":987, "value5":654});

I am not expert in subdoc operations and @graham.pople able to answer that

1 Like

Thank you and it worked. Let’s wait for @graham.pople if he has better way to achieve via subdoc operations.

Hi @y2k1975
That code snippet will replace the contents of dict.nestedDict with the contents of getMap(), which is what you’re seeing.
So you want a way to merge a map with an existing one? There’s not a built-in Sub-Document spec for that, but if the new map has a small number of keys, you could loop over it and build it up manually? Like this:
JsonObject newMap;

        if (newMap.getNames().size() > 16) {
            throw new RuntimeException("Too many fields!");
        }

        List<MutateInSpec> specs = new ArrayList<>();
        for (String key : newMap.getNames()) {
            specs.add(MutateInSpec.upsert("dict.nestedDict." + key, newMap.getLong(key)).createPath());
        }

        collection.mutateIn(id, specs);

(nb I’ve written this example in SDK3 rather than SDK2, as SDK2 is only about 6 months off EOL at this point. But you can easily adapt the example for SDK2 of course.)

Of course, this does have the limitation that you can only support 16 fields in the map. If you have more then you could use @vsr1’s suggestion above, or do a full-document get-and-replace, or do multiple mutateIn calls.

1 Like

Thank you @graham.pople. At this point we are using 2.7 and I will check the same with this version. At this point we are having less than 16 fields and no possibility to go beyond that in near future. I will try with equivalent way to achieve using 2.7 version. Also @vsr1 is there is anything specific we need to build in index if we are using those queries.

Thanks