#javascript #node.js #mongodb #mongoose
#javascript #node.js #mongodb #mongoose
Вопрос:
У меня есть такая страница. И данные с моего сервера MongoDB.
Сначала я создаю коллекцию пользователей и помещаю эти пользовательские данные. Но я добавляю коллекцию счетчиков, потому что хочу показать их количество просмотров.
У каждого пользователя есть несколько страниц, а данные о количестве просмотров представляют собой сумму данных счетчика.
Пользовательские коллекции выглядят следующим образом, и мне нужны только логин, идентификационные (уникальные) данные.
Коллекция пользователей
{
"_id": {
"$oid": "5f7e92b88dc8f64cb4e6c2c0"
},
"login": "mojombo",
"id": 1,
"avatar_url": "https://avatars0.githubusercontent.com/u/1?v=4",
"url": "https://api.github.com/users/mojombo",
"html_url": "https://github.com/mojombo",
"type": "User",
"site_admin": "false",
"name": "Tom Preston-Werner",
"company": null,
"blog": "http://tom.preston-werner.com",
"location": "San Francisco",
"email": "tom@mojombo.com",
"hireable": null,
"bio": null,
"created_at": {
"$date": "2007-10-20T05:24:19.000Z"
},
"updated_at": {
"$date": "2020-09-22T15:50:44.000Z"
},
"registerDate": {
"$date": "2020-10-08T04:16:56.459Z"
},
"__v": 0
}
Коллекция счетчиков
{
"_id": {
"$oid": "5f8e5bde9054ba2477dc2c57"
},
"repoName": "ale",
"repoNumber": 171780764,
"userName": "technicalpickles",
"userNumber": 159,
"viewDate": "2020-10-20",
"count": 1
}
В коллекции счетчиков мне нужно только имя пользователя, поле count для вычисления данных счетчика.
Итак, я пытаюсь использовать цикл и агрегированный метод, но проблема в том, что пользовательских данных слишком много, поэтому мне приходится отправлять слишком много запросов на сервер. (Если у меня есть данные 10000 пользователей, я должен отправить 10000 запросов) Итак, я не должен использовать метод цикла for.
router.get(`/sitemap/0`, async (req, res, next) => {
let name;
let dataArray = [];
let pageNumber = (Number(req.params.page) * 10000); // Current Page Number
let nextPage = (Number(req.params.page) 1) * 10000; // Next Page Number
let pageResu< // Page Result
try {
let users = await User.find({}, 'login id').limit(1000)
for (let i = 0; i < 1000; i ) {
name = users[i].login
let counters = await Counter.aggregate([{
$match: {
id: users.id,
userName: users[i].login
}
},
{
$group: {
_id: `${users[i].login}`,
count: {
$sum: "$count"
}
}
}
])
dataArray.push(counters)
console.log(counters)
}
console.log(dataArray)
} catch (e) {
// throw an error
throw e;
}
res.render("sitemap", {
dataArray
})
});
Результат кодов
Итак, я хочу отправить один запрос, и я думаю, что он должен использовать метод ‘aggregate’. Но без «цикла for».
Я хочу присоединиться Users collection
, Counters collection
но я слышал, что в MongoDB и Mongoose нет функции объединения.
Я просто хочу, чтобы результат был таким. Есть ли способ сделать это так?
{
"_id": {
"$oid": "5f7e92b88dc8f64cb4e6c2c0"
},
"login": "mojombo", --------------Match login with counter collection 'userName' value
"id": 1, ------------------------Match id with counter collection 'id' value
"count": [Sum of counters count data and it should be Number] ------- Only this field is added
"avatar_url": "https://avatars0.githubusercontent.com/u/1?v=4",
"url": "https://api.github.com/users/mojombo",
"html_url": "https://github.com/mojombo",
"type": "User",
"site_admin": "false",
"name": "Tom Preston-Werner",
"company": null,
"blog": "http://tom.preston-werner.com",
"location": "San Francisco",
"email": "tom@mojombo.com",
"hireable": null,
"bio": null,
"created_at": {
"$date": "2007-10-20T05:24:19.000Z"
},
"updated_at": {
"$date": "2020-09-22T15:50:44.000Z"
},
"registerDate": {
"$date": "2020-10-08T04:16:56.459Z"
},
"__v": 0
}
Ответ №1:
$lookup
при сборе счетчиков с использованием этапа конвейера, позвольте передать 2 поляid, login
для сопоставления с коллекцией счетчиков$match
условия обоих полей$addFields
дляcount
суммирования поля count из массива counters, используя$reduce
цикл итерации и$add
суммирования значений поля count$skip
для разбивки на страницы$limit
передайте свой лимит документов
let page = 1; // start pagination from first
let limit = 1000;
let skip = (page - 1) * limit;
let users = await User.aggregate([
{
$lookup: {
from: "counters",
let: {
id: "$id",
login: "$login"
},
pipeline: [
{
$match: {
$expr: {
$eq: ["$userName", "$$login"],
$eq: ["$userNumber", "$$id"]
}
}
}
],
as: "count"
}
},
{
$addFields: {
count: {
$reduce: {
input: "$count",
initialValue: 0,
in: { $add: ["$$value", "$$this.count"] }
}
}
}
},
{ $skip: skip },
{ $limit: limit }
])
Комментарии:
1. Спасибо! Есть одно неправильное имя переменной, но я это исправлю! И это, наконец, работает! Я также редактирую новые коды Playground.