如何捕获MongoDB中对象内指定数组变更的变更流
MongoDB变更流过滤器:仅监听特定文档的inventory.0.APPLE变更
问题场景
需要配置MongoDB变更流,仅检测特定_id文档中inventory.0.APPLE字段(包括其子字段)的变更,同时忽略inventory.0.DiscountBin.APPLE的任何变更。现有过滤器未达到预期效果。
示例文档
{ "_id": { "$oid": "64d43991678e200790d54c01" }, "GroceryPlatform": "FruitBasket", "StoreName": "Fruit Kingdom", "groceryType": "Assorted", "storeID": "64d43991678e200790d54c01", "inventory": [{ "Discounts": "Online", "Info1": { "Layout": "Honeycomb", "Lighting": "Grid", "Fitout": "Modern Black", "Version": "12.2.0" }, "Info3": { "Eftpos": { "$numberInt": "51" }, "Version": "45.1.11" }, "EnergySaver": "ON", "NetworkInfo2": { "Hostname": "FruitBasket-010100", "IPAddress": "10.10.20.227" }, "APPLE": { "Quality": { "$numberDouble": "70.868" }, "Weight": { "$numberDouble": "0.291" }, "Color": { "$numberDouble": "0.78" }, "UsedBy": { "$numberDouble": "4.59" } }, "Time": "2023-08-20T08:50:27", "TotalStock": { "$numberInt": "24" }, "AverageCost": { "$numberInt": "19" }, "WASTE": { "PowerDelta": { "$numberInt": "45" } }, "DiscountBin": { "APPLE": { "Quality": { "$numberDouble": "70.868" }, "Weight": { "$numberDouble": "0.291" }, "Color": { "$numberDouble": "0.78" }, "UsedBy": { "$numberDouble": "4.59" } }, "Time": "2023-08-20T08:43:39" } }], "__v": { "$numberInt": "0" } }
现有过滤器问题
原过滤器直接判断updateDescription.updatedFields.inventory.0.APPLE是否存在,仅能捕获整个APPLE对象被替换的情况,无法匹配其子字段(如inventory.0.APPLE.Quality)的变更;同时无法区分目标APPLE和DiscountBin下的APPLE字段。
{ $match: { $and: [ { 'fullDocument._id': new mongoose.Types.ObjectId(documentId) }, { 'updateDescription.updatedFields': { $exists: true } }, { 'updateDescription.updatedFields.inventory.0.APPLE': { $exists: true } } ] } }
解决方案
通过$expr结合$objectToArray将updatedFields转为键值数组,再用$filter筛选符合路径规则的字段:
- 匹配以
inventory.0.APPLE开头的路径(包括整个对象和子字段) - 排除以
inventory.0.DiscountBin.APPLE开头的路径
完整过滤器代码:
{ $match: { 'fullDocument._id': new mongoose.Types.ObjectId(documentId), 'updateDescription.updatedFields': { $exists: true }, $expr: { $gt: [ { $size: { $filter: { input: { $objectToArray: '$updateDescription.updatedFields' }, cond: { $and: [ // 匹配目标APPLE路径(含子字段) { $regexMatch: { input: '$$this.k', regex: '^inventory\\.0\\.APPLE(\\.|$)' } }, // 排除DiscountBin下的APPLE路径 { $not: { $regexMatch: { input: '$$this.k', regex: '^inventory\\.0\\.DiscountBin\\.APPLE' } } } ] } } } }, 0 ] } } }
逻辑说明
$objectToArray: '$updateDescription.updatedFields':将更新字段的键值对转为[{k: 路径, v: 值}, ...]格式的数组$regexMatch:用正则匹配路径:^inventory\.0\.APPLE(\.|$):匹配inventory.0.APPLE本身,或其下的子字段(如inventory.0.APPLE.Quality)$not: { $regexMatch: ... }:排除所有inventory.0.DiscountBin.APPLE开头的路径
$size判断筛选后的数组长度大于0,说明存在符合条件的更新
内容的提问来源于stack exchange,提问作者yobyjoe
相关产品推荐
相关产品推荐

