I have modeled your problem in Jupyter Notebook using interactive Java - so I will share each relevant cell with you. It should give you the pertinent implementation you are looking for.
I started with a server with no records / clean / namespace truncated.
First, I will add 4 records with a nested map as a general example.
void addRecord(Integer keyIndex, String mapBinName, String mapKey1Val, String mapKey2Val, String subMapKey1Val, boolean addKey1){
MapPolicy mPolicy = new MapPolicy(MapOrder.UNORDERED, MapWriteFlags.DEFAULT);
WritePolicy wPolicy = new WritePolicy();
wPolicy.sendKey = true; //Optional, if you want to inspect the record key
Key myRecKey = new Key("test", "testset", Value.get("key"+keyIndex));
HashMap <String, Value> profileObj = new HashMap <String, Value>();
if(addKey1) { profileObj.put("Key1", Value.get(mapKey1Val)); }
profileObj.put("Key2", Value.get(mapKey2Val));
//Sub-map (optional)
HashMap <String, String> metaObj = new HashMap <String, String>();
metaObj.put("Key1", subMapKey1Val);
profileObj.put("subKey1", new MapValue(metaObj));
client.operate(wPolicy, myRecKey,
MapOperation.put(mPolicy, mapBinName, Value.get("profile"), new MapValue(profileObj) )
);
System.out.println("Rec added: [key "+keyIndex+"]: "+ client.get(null, myRecKey));
}
Insert the test records:
//Create test records
String binName = "myMapBin1";
addRecord(1, binName, "val11", "val12", "vals11", true);
addRecord(2, binName, "val21", "val22", "vals21", true);
addRecord(3, binName, "val31", "val32", "vals31", false);
addRecord(4, binName, null, "val42", "vals41", true);
Output: (Note: key3 and key4 have the two cases for nested key Key1
that you are interested in. (I added a nesting level just to show use of CTX
as well.)
Rec added: [key 1]: (gen:1),(exp:0),(bins:(myMapBin1:{profile={Key2=val12, Key1=val11, subKey1={Key1=vals11}}}))
Rec added: [key 2]: (gen:1),(exp:0),(bins:(myMapBin1:{profile={Key2=val22, Key1=val21, subKey1={Key1=vals21}}}))
Rec added: [key 3]: (gen:1),(exp:0),(bins:(myMapBin1:{profile={Key2=val32, subKey1={Key1=vals31}}}))
Rec added: [key 4]: (gen:1),(exp:0),(bins:(myMapBin1:{profile={Key2=val42, Key1=null, subKey1={Key1=vals41}}}))
Now, I will update all the records but expecting only case key3 and key4 to update. The updated key value is: val31_updated
and val41_updated
etc.
Code to do the update. (This filter expression is I believe what you are looking for.)
void updateRecord(Integer keyIndex, String mapBinName, String mapKey1Val){
MapPolicy mPolicy = new MapPolicy(MapOrder.UNORDERED, MapWriteFlags.DEFAULT);
WritePolicy wPolicy = new WritePolicy();
wPolicy.sendKey = true; //Optional, if you want to inspect the record key
Key myRecKey = new Key("test", "testset", Value.get("key"+keyIndex));
Expression mapKeyFilter = Exp.build(
Exp.eq(
MapExp.getByKey(MapReturnType.VALUE, Exp.Type.NIL, Exp.val("Key1"), Exp.mapBin(mapBinName), CTX.mapKey(Value.get("profile"))),
Exp.nil() )
);
wPolicy.filterExp = mapKeyFilter;
client.operate(wPolicy, myRecKey,
MapOperation.put(mPolicy, mapBinName, Value.get("Key1"), Value.get(mapKey1Val), CTX.mapKey(Value.get("profile")) )
);
System.out.println("Read record: [key "+keyIndex+"]: "+ client.get(null, myRecKey));
}
Run the update on all records, expect only Key1 missing or value null should update:
//Update all records, should only update ones with Key1 missing or Key1 value null
String binName = "myMapBin1";
updateRecord(1, binName, "val11_updated");
updateRecord(2, binName, "val21_updated");
updateRecord(3, binName, "val31_updated");
updateRecord(4, binName, "val41_updated");
Output:
Read record: [key 1]: (gen:1),(exp:0),(bins:(myMapBin1:{profile={Key2=val12, Key1=val11, subKey1={Key1=vals11}}}))
Read record: [key 2]: (gen:1),(exp:0),(bins:(myMapBin1:{profile={Key2=val22, Key1=val21, subKey1={Key1=vals21}}}))
Read record: [key 3]: (gen:2),(exp:0),(bins:(myMapBin1:{profile={Key2=val32, Key1=val31_updated, subKey1={Key1=vals31}}}))
Read record: [key 4]: (gen:2),(exp:0),(bins:(myMapBin1:{profile={Key2=val42, Key1=val41_updated, subKey1={Key1=vals41}}}))