Java使用MongoDB的$concat和UpdateOne更新子对象字符串字段报错求助
错误原因
你遇到的报错是因为普通的MongoDB更新操作不支持直接将$concat这类聚合表达式作为字段值传入$set,MongoDB会把你写的$concat识别为要存储的字段名,而$开头的字段名是MongoDB禁止存储的,因此抛出异常。
要实现你的需求,需要用MongoDB 4.2及以上版本支持的聚合管道更新能力,同时配合数组定位逻辑修改指定的数组成员字段,以下是两种可行的实现方案:
方案1:使用$map遍历数组实现(无需配置arrayFilters)
直接在聚合管道的$set阶段用$map遍历data数组,匹配到empCode等于EMP2的元素时,用$concat拼接lastname,其余元素保持原样返回即可,代码如下:
public class FixDataApp { public static void main(String[] args) throws IOException { MongoCollection<Document> collection = MongoConfig.getCollection(args[0], args[1], "myCollection"); // 构造$map逻辑遍历data数组 Bson mapLogic = Aggregates.$set(new BasicDBObject("data", new BasicDBObject("$map", new BasicDBObject("input", "$data") .append("as", "item") .append("in", new BasicDBObject("$cond", Arrays.asList( new BasicDBObject("$eq", Arrays.asList("$$item.empCode", "EMP2")), // 匹配到对应元素时修改lastname new BasicDBObject("$mergeObjects", Arrays.asList( "$$item", new BasicDBObject("lastname", new BasicDBObject("$concat", Arrays.asList("$$item.lastname", " TestAppendStr"))) )), // 不匹配的元素直接返回 "$$item" ))) )); // 用聚合管道形式执行更新 UpdateResult result = collection.updateOne( Filters.eq("_id", "61866c32d11c9aefb01125f7"), Arrays.asList(mapLogic) ); System.out.println("Record updated successfully " + result.getModifiedCount()); } }
方案2:使用数组更新过滤器实现(语法更简洁)
如果你更习惯用占位符定位数组元素,可以配合UpdateOptions配置数组过滤规则,代码如下:
public class FixDataApp { public static void main(String[] args) throws IOException { MongoCollection<Document> collection = MongoConfig.getCollection(args[0], args[1], "myCollection"); // 构造聚合更新的$set阶段 Bson update = Aggregates.$set( new BasicDBObject("data.$[empItem].lastname", new BasicDBObject("$concat", Arrays.asList("$data.$[empItem].lastname", " TestAppendStr")) ) ); // 配置数组过滤器:匹配empCode为EMP2的元素 UpdateOptions options = new UpdateOptions() .arrayFilters(Arrays.asList(Filters.eq("empItem.empCode", "EMP2"))); UpdateResult result = collection.updateOne( Filters.eq("_id", "61866c32d11c9aefb01125f7"), Arrays.asList(update), options ); System.out.println("Record updated successfully " + result.getModifiedCount()); } }
注意事项
- 两种方案都依赖MongoDB 4.2及以上版本的支持,如果你使用的是更低版本的MongoDB,需要先查询出文档,修改对应字段后再执行全量更新。
- 如果你的匹配条件不需要限制文档
_id,可以删除对应的Filters.eq("_id", ...)条件,实现批量更新所有符合要求的文档。
内容的提问来源于stack exchange,提问作者Vivek Buddhadev
相关产品推荐
相关产品推荐

