如何使用Spring Data删除MongoDB文档数组内匹配条件的元素
功能需求
需要在满足指定过滤条件时,删除MongoDB文档内caseDetails数组的匹配子元素:现有数千条记录,每条均包含caseDetails数组,数组内存有多个子项,传入caseId参数后,删除所有符合过滤条件的文档中caseDetails数组里caseId与传入值匹配的子项,无需额外编写新查询逻辑。
初始数据库示例数据
{ "_id": "60f8fcbe8f67d30784c45561", "messageType": "e", "sendDate": "2021-07-22T05:06:04.023Z", "assigneeId": 600003, "customerId": 58004, "subject": "Email Test 1[#24894006]", "mailAnswered": false, "hasAttachments": false, "caseDetails": [ { "caseId": 24894006, "employeeId": 600003 }, { "caseId": 34894006, "employeeId": 600003 }, { "caseId": 44894006, "employeeId": 600003 } ] }, { "_id": "60f8fcbe8f67d30784c45561", "messageType": "e", "sendDate": "2021-07-22T05:06:04.023Z", "assigneeId": 600003, "customerId": 58004, "subject": "Email Test 1[#24894006]", "mailAnswered": false, "hasAttachments": false, "caseDetails": [ { "caseId": 24894006, "employeeId": 600003 }, { "caseId": 34894006, "employeeId": 600003 }, { "caseId": 44894006, "employeeId": 600003 } ] }
预期结果(删除caseId=24894006的对应子项后)
{ "_id": "60f8fcbe8f67d30784c45561", "messageType": "e", "sendDate": "2021-07-22T05:06:04.023Z", "assigneeId": 600003, "customerId": 58004, "subject": "Email Test 1[#24894006]", "mailAnswered": false, "hasAttachments": false, "caseDetails": [ { "caseId": 34894006, "employeeId": 600003 }, { "caseId": 44894006, "employeeId": 600003 } ] }, { "_id": "80f8fcbe8f67d30784c45561", "messageType": "e", "sendDate": "2021-07-22T05:06:04.023Z", "assigneeId": 600003, "customerId": 58004, "subject": "Email Test 1[#24894006]", "mailAnswered": false, "hasAttachments": false, "caseDetails": [ { "caseId": 54894006, "employeeId": 600003 }, { "caseId": 64894006, "employeeId": 600003 } ] }
现有代码
接口实现代码
@Override public List<Email> unlinkMessageCaseDetailsByCaseId(MessageFilter messageFilter) { Criteria finalCriteria = handleCriteria(messageFilter); Query query = query(finalCriteria); // Update update = new Update().pull("caseDetails", Collections.singletonMap("caseId", messageFilter.getCaseId())); List<Email> uMono = mongoTemplate.find(query, Email.class).collectList().block(); return uMono; }
Repository定义
@MongoRepository public interface EmailRepository extends ReactiveCrudRepository<Email, String>, MessageRepositoryCustom { }
正确实现方式
你注释中的pull操作思路是正确的,只需要补充执行更新的逻辑即可,完整实现如下:
@Override public List<Email> unlinkMessageCaseDetailsByCaseId(MessageFilter messageFilter) { Criteria finalCriteria = handleCriteria(messageFilter); Query query = query(finalCriteria); // 构造数组删除规则:删除caseDetails中caseId匹配传入参数的子项 Update update = new Update().pull("caseDetails", Collections.singletonMap("caseId", messageFilter.getCaseId())); // 批量更新所有符合条件的文档 mongoTemplate.updateMulti(query, update, Email.class).block(); // 返回更新后的匹配文档列表 return mongoTemplate.find(query, Email.class).collectList().block(); }
补充说明
pull是MongoDB原生的数组操作符,会自动遍历所有匹配文档的caseDetails数组,删除所有符合条件的子元素,不需要手动遍历文档,性能足以应对数千条量级的数据- 如果需要返回更新前的文档,可以使用
findAndModify方法,配置ReturnDocument.BEFORE参数即可将更新和查询合并为一次请求 - 如果不需要同步返回结果,建议移除
block()调用直接返回Flux<Email>,符合响应式编程规范
内容的提问来源于stack exchange,提问作者Shrey Soni
相关产品推荐
相关产品推荐

