如何获取水果数组中只有 2 个或更多香蕉的 json 对象?
How to get the json object with only 2 or more bananas in the fruits array?
我有这个猫鼬模式。
const storeSchema = mongoose.Schema({
name: {
type: String,
required: true,
},
fruits: {
type: [String],
required: true,
},
});
而且我需要获取水果数组中所有包含 2 个或更多香蕉的对象,就像这样。
{
"name": "Beautiful Store",
"fruits": ["banana", "apple", "banana", "pear"]
}
我正在尝试类似的方法,但没有成功...
const query = await StoreModel.find({ fruits: { $gd: 2 } })
像这样:
选项 1:(效率较低但直观)
db.collection.aggregate([
{
$addFields: {
numBananas: {
$size: {
$filter: {
input: "$fruits",
as: "item",
cond: {
$eq: [
"$$item",
"banana"
]
}
}
}
}
}
},
{
$match: {
numBananas: {
$gte: 2
}
}
},
{
$project: {
name: 1,
fruits: 1
}
}
])
解释:
- 添加带有香蕉数量的字段“numBananas”
- 仅过滤具有 >=2 个 banas 的文档
- 只投射必要的产出
选项 2:(最佳,灵感来自下方的 Buzz :))
db.collection.aggregate([
{
$match: {
$expr: {
$gte: [
{
$size: {
$filter: {
input: "$fruits",
as: "item",
cond: {
$eq: [
"$$item",
"banana"
]
}
}
}
},
2
]
}
}
},
{$sort:{name:1}}
])
解释:
只匹配那些有 >=2 bananas 的,最好是在 fruits 上创建索引
(我认为这个解决方案与下面 Buzz 的 $reduce 选项有 50/50 的性能竞争,我会打赌这个)
这里有两个主题变体。
第一个使用$reduce
直接计算香蕉的数量(本质上就是上面的{$size:{$filter...}}
。为了额外的性能,我们将calc和$match
一起放在一个单级:
db.foo.aggregate([
{$match: {$expr: {$gte: [
{$reduce: {
input: '$fruits',
initialValue: 0,
in: {$cond:[{$eq: ['$$this','banana']}, {$add:['$$value',1]}, '$$value']}
}}, 2]}
}}
]);
第二个是通用水果计数器,以防您想要更复杂的表达式,例如>=2 个香蕉或(1 个梨和 1 个苹果)。它确实需要 $unwind/$group
.
的成本
c=db.foo.aggregate([
{$unwind: '$fruits'}
,{$group: {_id: {id: '$_id', f: '$fruits'}, N: {$sum:1}}}
,{$match: {'_id.f': 'banana', N:{$gte:2}} }
]);
我有这个猫鼬模式。
const storeSchema = mongoose.Schema({
name: {
type: String,
required: true,
},
fruits: {
type: [String],
required: true,
},
});
而且我需要获取水果数组中所有包含 2 个或更多香蕉的对象,就像这样。
{
"name": "Beautiful Store",
"fruits": ["banana", "apple", "banana", "pear"]
}
我正在尝试类似的方法,但没有成功...
const query = await StoreModel.find({ fruits: { $gd: 2 } })
像这样:
选项 1:(效率较低但直观)
db.collection.aggregate([
{
$addFields: {
numBananas: {
$size: {
$filter: {
input: "$fruits",
as: "item",
cond: {
$eq: [
"$$item",
"banana"
]
}
}
}
}
}
},
{
$match: {
numBananas: {
$gte: 2
}
}
},
{
$project: {
name: 1,
fruits: 1
}
}
])
解释:
- 添加带有香蕉数量的字段“numBananas”
- 仅过滤具有 >=2 个 banas 的文档
- 只投射必要的产出
选项 2:(最佳,灵感来自下方的 Buzz :))
db.collection.aggregate([
{
$match: {
$expr: {
$gte: [
{
$size: {
$filter: {
input: "$fruits",
as: "item",
cond: {
$eq: [
"$$item",
"banana"
]
}
}
}
},
2
]
}
}
},
{$sort:{name:1}}
])
解释: 只匹配那些有 >=2 bananas 的,最好是在 fruits 上创建索引 (我认为这个解决方案与下面 Buzz 的 $reduce 选项有 50/50 的性能竞争,我会打赌这个)
这里有两个主题变体。
第一个使用$reduce
直接计算香蕉的数量(本质上就是上面的{$size:{$filter...}}
。为了额外的性能,我们将calc和$match
一起放在一个单级:
db.foo.aggregate([
{$match: {$expr: {$gte: [
{$reduce: {
input: '$fruits',
initialValue: 0,
in: {$cond:[{$eq: ['$$this','banana']}, {$add:['$$value',1]}, '$$value']}
}}, 2]}
}}
]);
第二个是通用水果计数器,以防您想要更复杂的表达式,例如>=2 个香蕉或(1 个梨和 1 个苹果)。它确实需要 $unwind/$group
.
c=db.foo.aggregate([
{$unwind: '$fruits'}
,{$group: {_id: {id: '$_id', f: '$fruits'}, N: {$sum:1}}}
,{$match: {'_id.f': 'banana', N:{$gte:2}} }
]);