Задать вопрос
ms-dred
@ms-dred
Вечно что то не то и что то не так...

Как более правильно сделать выборку для просмотра популярных записей за определенный срок?

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

Для того чтобы это реализовать пришлось сделать новую коллекцию Counts
Схема mongoose
var schema = new Schema({
    href: 		{ type: String }, // URL document.url
    count: 		{ type: Number, default: 1 }, // вообще 1, но тут и фейковые просмотры (random 1-5)
    createdAt: 	{ type: Date, default: Date.now }
})

Добавлен мидлвар которые по нужному URL создаем дополнительную запись в Counts
Есть так же коллекция Documents, примерно такой структуры
var schema = new Schema({
    url: 		{ type: String }, // URL document.url
    createdAt: 	{ type: Date, default: Date.now }
})

Т.е. Counts.href === Documents.url

По обработчику
1. Сначала делаю запрос в Counts и подсчитываю поля count
return Counts.aggregate([
        {
            $match: { createdAt: { $gte: new Date(n.setDate(n.getDate() - 1 )) } }
        }, {
            $project: {
                _id: 1,
                href: 1,
                count: 1
            }
        }, {
            $group: {
                _id: "$href",
                count: {
                    $sum: "$count"
                }
            }
        }, {
            $sort: { count: -1 }
        }, {
            $skip: request.skip
        }, {
            $limit: 12
        }
    ])

На выходе получаю массив документов вида
[
    {
         _id: "Documents.url",
         count: 5000
    }
    //... и так 12 записей
]

Запрос выполняет долго, много данных в коллекции, индекс по полю createdAt создан, возможно есть более быстрый способ получить сумму документов, может я делаю что то не так?

После выборке в Counts, создаю массив _id (они же Counts.href) и делаю новую выборку для формирования документов из Documents
return Documents
        .aggregate([
            { $match: { url: { $in: ["Counts.href","Counts.href", "Counts.href", "Counts.href"] } } },
            {
                $project: {
                    _id: 1,
                    url: 1,
                    text: 1,
                    // тут еще куча всего
            }, {
                $group: {
                    _id: "$_id",
                    url: { $first: "$url" },
                    text: { $first: '$text' }
                }
            }
        ])
        .then(e => {
            return Promise.all(e.map(async document => {
                return Promise.all(request.itemsCounts.map(async count => {
                    if(document.url === count._id) return document.count = count.count
                })).then(e => {
                    return document
                })
            }))
        })

Так же вопрос как упростить конструкцию в обещании? Может есть более правильное решение, хотя если учесть что там всего 12 документов, эта конструкция работает очень быстро.

Будет супер если подскажите что то или ткнете пальцем на ошибки, быть может вообще саму логику надо переделывать на какую то более правильную
  • Вопрос задан
  • 41 просмотр
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы