#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"
}
}
])