MongoDB查询:如何筛选可用现有食材制作的所有食谱
解决食谱匹配的MongoDB查询问题
你需要的是找出所有食材种类都被手头食材覆盖的食谱,而非恰好仅包含指定食材的食谱。原查询的问题在于用$size限制了食材数量,且$all的逻辑方向不对——它只确保手头食材都在食谱里,而非食谱食材都在手头里。
推荐方案:用$expr + $setIsSubset
MongoDB的$setIsSubset操作符可以直接判断一个集合是否是另一个集合的子集,完美匹配你的需求。假设手头食材数组为['banana', 'milk', 'apple'],查询语句如下:
db.recipes.find({ $expr: { $setIsSubset: [ "$ingredients.name", // 自动提取当前食谱的所有食材名称组成数组 ["banana", "milk", "apple"] // 你的手头食材列表 ] } })
这个查询会返回所有满足「食谱的每一种食材都在手头食材中」的文档,不管你手头多了多少额外食材,也不管食谱本身有几种食材。
替代方案:反向排除不匹配的食谱
通过$not和$elemMatch,排除那些包含手头没有的食材的食谱:
db.recipes.find({ "ingredients.name": { $not: { $elemMatch: { $nin: ["banana", "milk", "apple"] } } } })
逻辑是:食谱中不存在任何一种食材,其名称不在手头食材列表里——等同于所有食材都符合要求。
原查询的问题分析
$all:['banana', 'milk']仅确保食谱同时包含这两种食材,但无法阻止食谱包含其他你没有的食材(比如橙子),会返回不符合要求的结果。ingredients: {$size:2}强制要求食谱恰好有2种食材,会过滤掉食材更少的有效食谱(比如仅需香蕉的食谱),也不符合需求。
扩展:考虑食材数量匹配
如果需要校验食材数量(比如手头香蕉数量≥食谱所需),可以在查询中加入数量条件:
db.recipes.find({ $expr: { $setIsSubset: ["$ingredients.name", ["banana", "milk", "apple"]] }, "ingredients": {$elemMatch: {name: "banana", qty: {$lte: 3}}}, "ingredients": {$elemMatch: {name: "milk", qty: {$lte: 2}}} })
这里假设你手头有3个香蕉、2杯牛奶,会筛选出数量符合要求的食谱。
内容的提问来源于stack exchange,提问作者Danf
相关产品推荐
相关产品推荐

