问题描述
假设我的数据库如下,
const data = [
{
"chapter": 1,"targets": [
{
type: 'user',recipientId: 1
}
],"challenge": [
{
"activate": true,"challengeId": "ch-1"
},{
"activate": true,"challengeId": "ch-2"
},"challengeId": "ch-3"
},]
},{
"chapter": 1,recipientId: 2
}
],"challengeId": "ch-4"
},recipientId: 3
}
],"challengeId": "ch-5"
},recipientId: 4
}
],{
"activate": false,],
,如果要输入,我想使用recipientId
数组进行查询
[1,2]
应当与预期输出为challengeId
的交点
[
{"challengeId": "ch-2"},{"challengeId": "ch-3"}
]
如果输入为[1,2,3]
,则应返回[]
,因为与此输入没有交集
如果输入为[1,4]
,则也返回
[
{"challengeId": "ch-2"},]
因为challengeId ch-3
中的recipientId 4
尚未激活。
我一直在读$setIntersection
,但似乎无法解决我的问题。
有什么建议吗? 谢谢。
解决方法
我认为使用此查询可以非常接近您的结果。您可能只想清理结果。
const input = [1,2,4]
db.test.aggregate([
//filter by input array
{ $match: { "targets.recipientId": { $in: input } } },// Unwind the challenge array
{ $unwind: "$challenge" },//filter out the non-active ones
{ $match: { "challenge.activate": true } },//group by challengeId and keep track of the count
{ $group: { _id: "$challenge.challengeId",count: { $sum: 1 } } },//filter out the challengeId with count < input.length
{ $match: { count: { $gte: input.length } } },]);
result: {"_id":"ch-2","count":3}
,
您需要实现一些自定义逻辑,因为$setIntersecion
无法接受动态数组字段,
-
$match
至recipientId
字段 -
$project
过滤挑战是activate: ture
-
$group
(以null表示)以计算文档总数 -
$unwind
挑战数组2次,因为我们出于计数目的将其分组在上面 -
$group
bychallengeId
并获得挑战计数 -
$match
检查文档总数和挑战总数是否相同 -
$project
以显示必填字段
db.collection.aggregate([
{ $match: { "targets.recipientId": { $in: [1,4] } } },{
$project: {
challenge: {
$filter: {
input: "$challenge",cond: { $eq: ["$$this.activate",true] }
}
}
}
},{
$group: {
_id: null,challenge: { $push: "$challenge" },count: { $sum: 1 }
}
},{ $unwind: "$challenge" },{
$group: {
_id: "$challenge.challengeId",cCount: { $sum: 1 },count: { $first: "$count" }
}
},{ $match: { $expr: { $eq: ["$count","$cCount"] } } },{
$project: {
_id: 0,challengeId: "$_id"
}
}
])