Mongoose查询ingredients全部元素属于inventory的文档返回零结果
问题原因
你当前使用$all的逻辑完全和需求相反:ingredients: { $all: inventory }的语义是要求ingredients数组包含inventory数组的所有元素,而你的需求是ingredients数组的每一个元素都至少能匹配到inventory中的一个关键词,自然返回空结果。
解决方案
方案1:基于现有结构直接查询(无需改数据)
你可以使用聚合查询实现需求,逻辑是统计每个文档的ingredients中无法匹配inventory关键词的元素数量,筛选数量为0的文档即可:
首先保留你将inventory转为不区分大小写正则的逻辑:
let inventory = ["lemons", "butter", "egg", "milk", "bread", "salmon", "asparagus", "pepper"]; const inventoryRegex = inventory.map(i => new RegExp(i, "i"));
之后执行聚合查询:
Recipe.aggregate([ { $addFields: { // 统计未匹配任何关键词的食材数量 unMatchedCount: { $size: { $filter: { input: "$ingredients", cond: { $not: { $or: inventoryRegex.map(regex => ({ $regexMatch: { input: "$$this", regex: regex } })) } } } } } } }, // 未匹配数量为0即符合要求 { $match: { unMatchedCount: 0 } }, // 可选:删除临时统计字段 { $unset: "unMatchedCount" } ])
该方案在数千条数据的场景下性能完全可用。
方案2:优化结构提升查询性能
如果后续数据量增长,可以提前将每个ingredients中的食材关键词提取为单独的数组字段,比如新增ingredientKeys字段,示例结构如下:
{ recipe: "recipe2", ingredients: [ "2 lemons", "2 tbsp butter", "1 large egg" ], ingredientKeys: [ "lemons", "butter", "egg" ] }
优化后查询可以完全避免正则匹配,性能提升明显:
Recipe.find({ ingredientKeys: { $not: { $elemMatch: { $nin: inventory } } } })
该查询的逻辑是:不存在任何一个ingredientKeys元素不在inventory数组中,即所有食材关键词都在你的库存范围内。
内容的提问来源于stack exchange,提问作者Jarki
相关产品推荐
相关产品推荐

