MongoDB如何从子文档数组中删除匹配指定条件的子文档
问题解答
首先明确结论:你的需求可以实现,原生$pull操作符本身不支持$dateFromString这类聚合运算符,所以无法直接用普通$pull语句处理字符串格式的日期转换逻辑,但你可以通过两种方式实现等价效果:
方案1:日期字符串为标准YYYY-MM-DD格式时直接用$pull
如果你的tests.date字段存储的是标准YYYY-MM-DD格式的字符串,字符串的字典序和日期顺序完全一致,可直接用普通$pull实现,写法最简单:
db.Vaccinations.updateMany( {}, // 可添加前置匹配条件缩小处理范围,提升性能 { $pull: { tests: { date: { $gte: "2019-02-22" }, "attending.id": "0187" } } } )
如果要缩小处理范围,可在第一个参数添加匹配条件,只处理存在符合删除条件元素的文档:
db.Vaccinations.updateMany( { "tests.attending.id": "0187", "tests.date": { $gte: "2019-02-22" } }, { $pull: { tests: { date: { $gte: "2019-02-22" }, "attending.id": "0187" } } } )
方案2:日期格式不标准时用聚合管道更新
如果你的日期字符串不是标准格式,需要用$dateFromString转换,可使用MongoDB 4.2及以上版本支持的聚合管道式更新,通过$filter过滤数组实现和$pull完全等价的效果:
db.Vaccinations.updateMany( {}, // 同样可添加前置匹配条件缩小范围 [ { $set: { tests: { $filter: { input: "$tests", cond: { $not: { $and: [ { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, ISODate("2019-02-22T00:00:00Z") ] }, { $in: [ "0187", "$$this.attending.id" ] } ] } } } } } } ] )
逻辑说明:$filter遍历tests数组的每个元素($$this指代当前遍历的test子文档),仅保留不满足删除条件的元素,等价于移除所有符合要求的子文档。
原有写法的问题
- 普通
$pull的查询条件不支持$dateFromString这类聚合运算符,无法直接处理日期转换逻辑 - 原有聚合的匹配逻辑中直接使用
$tests.date会返回整个tests数组的所有日期,不是针对单个test子文档的日期做判断,匹配逻辑本身就不正确
内容的提问来源于stack exchange,提问作者Andrea
相关产品推荐
相关产品推荐

