Mongodb从输入数组的数组字段中找到子集

问题描述

假设我的数据库如下,

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无法接受动态数组字段,

  • $matchrecipientId字段
  • $project过滤挑战是activate: ture
  • $group(以null表示)以计算文档总数
  • $unwind挑战数组2次,因为我们出于计数目的将其分组在上面
  • $group by challengeId并获得挑战计数
  • $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"
    }
  }
])

Playground