#node.js #mongodb #mongoose #aggregation-framework
#node.js #mongodb #мангуст #агрегация-фреймворк
Вопрос:
У меня есть две коллекции. Коллекция «пользователи» и коллекция «события». В коллекции событий есть первичный ключ, который указывает, какому пользователю принадлежит событие.
Я хотел бы подсчитать, сколько событий у пользователя соответствует определенному условию.
В настоящее время я выполняю это следующим образом:
db.users.find({ usersMatchingACondition }).forEach(user => {
const eventCount = db.events.find({
title: 'An event title that I want to find',
userId: user._id
}).count();
print(`This user has ${eventCount} events`);
});
В идеале я хотел бы вернуть массив или объект с идентификатором пользователя и количеством событий, которые есть у этого пользователя.
С 10 000 пользователями — это, очевидно, создает 10 000 запросов, и я думаю, что это можно было бы сделать намного эффективнее!
Я предполагаю, что это легко с помощью какого-то агрегированного запроса, но я не знаком с синтаксисом и изо всех сил пытаюсь разобраться в этом.
Любая помощь была бы высоко оценена!
Ответ №1:
Вам нужен $ lookup, чтобы получить данные из events
сопоставления user_id
. Затем вы можете использовать $filter для применения вашего условия на уровне события, а для получения подсчета вы можете использовать оператор $size
db.users.aggregate([
{
$match: { //users matching condition }
},
{
$lookup:
{
from: 'events',
localField: '_id', //your "primary key"
foreignField: 'user_id',
as: 'user_events'
}
},
{
$addFields: {
user_events: {
$filter: {
input: "$user_events",
cond: {
$eq: [
'$$this.title', 'An event title that I want to find'
]
}
}
}
}
},
{
$project: {
_id: 1,
// other fields you want to retrieve: 1,
totalEvents: { $size: "$user_events" }
}
}
])
Ответ №2:
Без aggregate не так много оптимизации, но поскольку вы специально сказали, что
Во-первых, вместо
const eventCount = db.events.find({
title: 'An event title that I want to find',
userId: user._id
}).count();
Делать
const eventCount = db.events.count({
title: 'An event title that I want to find',
userId: user._id
});
Это значительно ускорит ваши запросы, потому что запрос find фактически сначала извлекает документы, а затем выполняет подсчет.
Для возврата массива вы можете просто инициализировать массив в начале и поместить в него объекты {userid: id, count: eventCount}.