Mongodb находит подмножество в поле массива из входного массива

#javascript #mongodb #mongoose #nosql

#javascript #mongodb #мангуст #nosql

Вопрос:

Предположим, у меня есть БД, как показано ниже,

 const data = [
  {
    "chapter": 1,
    "targets": [
      {
        type: 'user',
        recipientId: 1
      }
    ],
    "challenge": [
      {
        "activate": true,
        "challengeId": "ch-1"
      },
      {
        "activate": true,
        "challengeId": "ch-2"
      },
      {
        "activate": true,
        "challengeId": "ch-3"
      },
    ]
  },
  {
    "chapter": 1,
    "targets": [
      {
        type: 'user',
        recipientId: 2
      }
    ],
    "challenge": [
      {
        "activate": true,
        "challengeId": "ch-2"
      },
      {
        "activate": true,
        "challengeId": "ch-3"
      },
      {
        "activate": true,
        "challengeId": "ch-4"
      },
    ]
  },
  {
    "chapter": 1,
    "targets": [
      {
        type: 'user',
        recipientId: 3
      }
    ],
    "challenge": [
      {
        "activate": true,
        "challengeId": "ch-4"
      },
      {
        "activate": true,
        "challengeId": "ch-5"
      },
    ]
  },
  {
    "chapter": 1,
    "targets": [
      {
        type: 'user',
        recipientId: 4
      }
    ],
    "challenge": [
      {
        "activate": true,
        "challengeId": "ch-2"
      },
      {
        "activate": false,
        "challengeId": "ch-3"
      },
      {
        "activate": true,
        "challengeId": "ch-4"
      },
    ]
  },
],
  

и я хочу запросить, используя массив recipientId , если я введу
[1,2] , он должен превратить пересечение challengeId ожидаемого результата в

 [
{"challengeId": "ch-2"},
{"challengeId": "ch-3"}
]
  

если ввод [1,2,3] , он должен вернуться [] , потому что с этим входом нет пересечения

и если ввод [1,2,4] также возвращает

 [
{"challengeId": "ch-2"},
]
  

из challengeId ch-3 recipientId 4 -за еще не активируется.

Я читал $setIntersection , но, похоже, это не решает мою проблему.

Есть предложения? Спасибо.

Ответ №1:

Я думаю, вы можете приблизиться к своему результату, используя этот запрос. Возможно, вы просто захотите очистить результат.

 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}
  

Комментарии:

1. Я попробовал ваш код, он кажется правильным, как я и ожидал. Для этого нужно протестировать много случаев. Спасибо за вашу помощь.

Ответ №2:

Вам необходимо реализовать некоторую пользовательскую логику, поскольку $setIntersecion он не может принимать динамическое поле массива,

  • $match в recipientId поле
  • $project для фильтрации проблем activate: ture
  • $group по null для подсчета общего количества документов
  • $unwind проверяет массив 2 раза, потому что мы сгруппировали его выше для подсчета
  • $group challengeId и получает количество вызовов
  • $match для проверки общего количества документов и количества запросов одинаковы
  • $project для отображения обязательных полей
 db.collection.aggregate([
  { $match: { "targets.recipientId": { $in: [1, 2, 4] } } },
  {
    $project: {
      challenge: {
        $filter: {
          input: "$challenge",
          cond: { $eq: ["$$this.activate", true] }
        }
      }
    }
  },
  {
    $group: {
      _id: null,
      challenge: { $push: "$challenge" },
      count: { $sum: 1 }
    }
  },
  { $unwind: "$challenge" },
  { $unwind: "$challenge" },
  {
    $group: {
      _id: "$challenge.challengeId",
      cCount: { $sum: 1 },
      count: { $first: "$count" }
    }
  },
  { $match: { $expr: { $eq: ["$count", "$cCount"] } } },
  {
    $project: {
      _id: 0,
      challengeId: "$_id"
    }
  }
])
  

Игровая площадка