原生Mongo从3.6以上可以使用$[
操作符批量修改内嵌数组元素,以下是基于mongoTemplate的封装实现:
/**
* MonogoDB 更新操作符
*/
@Getter
@AllArgsConstructor
public enum UpdateOperator {
//
INC("$inc"),
SET("$set");
String code;
}
/**
* 更新内嵌数组指定元素
*
* @param query 更新的文档查询条件
* @param arrayName 更新的内嵌数组名
* @param updateMap 对内嵌数组元素不同操作的更新map
* @param eleFilter 更新内嵌数组元素的过滤条件
* @return
*/
public UpdateResult updateArrayElement(Criteria query, String arrayName, Map<UpdateOperator, JSONObject> updateMap, Criteria eleFilter){
BasicDBObject update = new BasicDBObject();
UpdateOptions updateOptions = new UpdateOptions();
// 设置$set和$inc等操作符对应的元素更新
for (UpdateOperator operator : updateMap.keySet()){
BasicBSONObject eleSetBson = new BasicBSONObject();
JSONObject eleSetJson = updateMap.get(operator);
for (String key : eleSetJson.keySet()){
eleSetBson.put(arrayName.concat(".$[item].").concat(key), eleSetJson.get(key));
}
update.put(operator.getCode(), eleSetBson);
}
BasicDBObject eleFilterBson = new BasicDBObject();
Document filter = eleFilter.getCriteriaObject();
for (String key : filter.keySet()){
eleFilterBson.put("item.".concat(key), filter.get(key));
}
updateOptions.arrayFilters(Lists.newArrayList(eleFilterBson));
return mongoTemplate.getCollection(tabName).updateMany(
query.getCriteriaObject(),
update,
updateOptions
);
}
假设有以下数据,实现将"_id":"id"
文档中sex为1的des设为"男",age加2:
{
"_id":"id",
"users":[
{
"uid":2,
"sex":1,
"age":23,
"des":"",
"name":"Alex"
},
{
"uid":3,
"sex":1,
"age":33,
"des":"",
"name":"Bob"
},
{
"uid":4,
"sex":0,
"age":20,
"des":"",
"name":"Cat"
},
]
}
public void demo(){
Map<UpdateOperator, JSONObject> updateMap = new HashMap<>();
JSONObject setJson = new JSONObject();
JSONObject incJson = new JSONObject();
setJson.put("des", "男");
incJson.put("age", 2);
updateMap.put(UpdateOperator.SET, setJson);
updateMap.put(UpdateOperator.INC, incJson );
// 批量设置用户的状态
updateArrayElement(
Criteria.where("_id").is("id"),
"users",
updateMap,
Criteria.where("sex").is(1)
);
}