问题
Document stored in mongodb:
{
"CNF_SERVICE_ID":"1",
"SERVICE_CATEGORY":"COMMON_SERVICE",
"SERVICES":[{
"SERVICE_NAME":"Authentication Service",
"VERSIONS":[{
"VERSION_NAME":"AuthenticationServiceV6_3",
"VERSION_NUMBER":"2",
"VERSION_NOTES":"test",
"RELEASE_DATE":"21-02-2020",
"OBSOLETE_DATE":"21-02-2020",
"STATUS":"Y",
"GROUPS":[{
"GROUP_NAME":"TEST GROUP",
"CREATED_DATE":"",
"NODE_NAMES":[
""
],
"CUSTOMERS":[{
"CUSTOMER_CONFIG_ID":"4",
"ACTIVATION_DATE":"21-02-2020",
"DEACTIVATION_DATE":"21-02-2020",
"STATUS":"Y"
}]
}]
}]
}
]
}
Now, I need to add another customer json to the array "CUSTOMERS" inside "GROUPS" in the same document above. The customer json would be like this:
{
"CUSTOMER_CONFIG_ID":"10",
"ACTIVATION_DATE":"16-03-2020",
"DEACTIVATION_DATE":"16-03-2021",
"STATUS":"Y"
}
I tried this:
Update update = new Update().push("SERVICES.$.VERSIONS.GROUPS.CUSTOMERS",customerdto);
mongoOperations.update(query, update, Myclass.class, "mycollection");
But, I am getting the exception: org.springframework.data.mongodb.UncategorizedMongoDbException: Command failed with error 28 (PathNotViable): 'Cannot create field 'GROUPS' in element
[ EDIT ADD ]
I was able to update it using the filtered positional operator. Below is the query I used:
update(
{ "SERVICE_CATEGORY":"COMMON_SERVICE", "SERVICES.SERVICE_NAME":"Authentication Service", "SERVICES.VERSIONS.VERSION_NAME":"AuthenticationServiceV6_3"},
{ $push:{"SERVICES.$[].VERSIONS.$[].GROUPS.$[].CUSTOMERS": { "CUSTOMER_CONFIG_ID":"6", "ACTIVATION_DATE":"31-03-2020", "STATUS":"Y" } } }
);
Actually, this query updated all the fields irrespective of the filter conditions. So. I tried this but I am facing syntax exception. Please help.
update(
{"SERVICE_CATEGORY":"COMMON_SERVICE"},
{"SERVICES.SERVICE_NAME":"Authentication Service"},
{"SERVICES.VERSIONS.VERSION_NAME":"AuthenticationServiceV6_3"}
{
$push:{"SERVICES.$[service].VERSIONS.$[version].GROUPS.$[group].CUSTOMERS":{
"CUSTOMER_CONFIG_ID":"6",
"ACTIVATION_DATE":"31-03-2020",
"STATUS":"Y"
}
}
},
{
multi: true,
arrayFilters: [ { $and:[{ "version.VERSION_NAME": "AuthenticationServiceV6_3"},{"service.SERVICE_NAME":"Authentication Service"},{"group.GROUP_NAME":"TEST GROUP"}]} ]
}
);
Update: April 1,2020
The code I tried:
validationquery.addCriteria(Criteria.where("SERVICE_CATEGORY").is(servicedto.getService_category()).and("SERVICES.SERVICE_NAME").is(servicedetail.getService_name()).and("SERVICES.VERSIONS.VERSION_NAME").is(version.getVersion_name()));
Update update=new Update().push("SERVICES.$[s].VERSIONS.$[v].GROUPS.$[].CUSTOMERS", customer).filterArray(Criteria.where("SERVICE_CATEGORY").is(servicedto.getService_category()).and("s.SERVICE_NAME").is(servicedetail.getService_name()).and("v.VERSION_NAME").is(version.getVersion_name()));
mongoOperations.updateMulti(validationquery, update, ServiceRegistrationDTO.class, collection, key,env);
The below exception is thrown:
ERROR com.sample.amt.mongoTemplate.MongoOperations - Exception in count(query, collectionName,key,env) :: org.springframework.dao.DataIntegrityViolationException: Error parsing array filter :: caused by :: Expected a single top-level field name, found 'SERVICE_CATEGORY' and 's'; nested exception is com.mongodb.MongoWriteException: Error parsing array filter :: caused by :: Expected a single top-level field name, found 'SERVICE_CATEGORY' and 's'
回答1:
This update query adds the JSON to the nested array, "SERVICES.VERSIONS.GROUPS.CUSTOMERS"
, based upon the specified filter conditions. Note that your filter conditions direct the update operation to the specific array (of the nested arrays).
// JSON document to be added to the CUSTOMERS array
new_cust = {
"CUSTOMER_CONFIG_ID": "6",
"ACTIVATION_DATE": "31-03-2020",
"STATUS": "Y"
}
db.collection.update(
{
"SERVICE_CATEGORY": "COMMON_SERVICE",
"SERVICES.SERVICE_NAME": "Authentication Service",
"SERVICES.VERSIONS.VERSION_NAME": "AuthenticationServiceV6_3"
},
{
$push: { "SERVICES.$[s].VERSIONS.$[v].GROUPS.$[g].CUSTOMERS": new_cust }
},
{
multi: true,
arrayFilters: [
{ "s.SERVICE_NAME": "Authentication Service" },
{ "v.VERSION_NAME": "AuthenticationServiceV6_3" },
{ "g.GROUP_NAME": "TEST GROUP" }
]
}
);
Few things to note when updating documents with nested arrays of more than one level nesting.
- Use the all positional operator
$[]
and the filtered positional operator$[<identifier>]
, and not the$
positional operator. With filtered positional operator specify the array filter conditions using thearrayFilters
parameter. Note that this will direct your update to target the specific nested array. - For the filtered positional operator
$[<identifier>]
, the identifier must begin with a lowercase letter and contain only alphanumeric characters.
References:
- Array Update Operators
- db.collection.update() with arrayFilters
回答2:
Thanks to @prasad_ for providing the query. I was able to eventually convert the query successfully to code with Spring data MongoTemplate's updateMulti method. I have posted the code below:
Query validationquery = new Query();
validationquery.addCriteria(Criteria.where("SERVICE_CATEGORY").is(servicedto.getService_category()).and("SERVICES.SERVICE_NAME").is(servicedetail.getService_name()).and("SERVICES.VERSIONS.VERSION_NAME").is(version.getVersion_name()));
Update update=new Update().push("SERVICES.$[s].VERSIONS.$[v].GROUPS.$[].CUSTOMERS", customer).filterArray(Criteria.where("s.SERVICE_NAME").is(servicedetail.getService_name())).filterArray(Criteria.where("v.VERSION_NAME").is(version.getVersion_name()));
mongoOperations.updateMulti(validationquery, update, ServiceRegistrationDTO.class, collection, key,env);
mongoTemplateobj.updateMulti(validationquery, update, ServiceRegistrationDTO.class, collection, key,env);
来源:https://stackoverflow.com/questions/60701824/how-to-add-a-json-in-a-nested-array-of-a-mongodb-document-using-spring