S
S
Stanislav2019-07-27 11:35:51
MongoDB
Stanislav, 2019-07-27 11:35:51

How to more correctly make a selection to view popular posts for a certain period?

The task was to make a selection of views per day, week and month, to do what I did and it works, but I think it can be done better, so I want to listen to the advice of those who have already done it or those who have experienced it.
In order to implement this, I had to make a new collection Counts
Scheme 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 }
})

A middleware has been added that, at the desired URL, we create an additional entry in Counts
. There is also a Documents collection, approximately of the following structure
var schema = new Schema({
    url: 		{ type: String }, // URL document.url
    createdAt: 	{ type: Date, default: Date.now }
})

Those. Counts.href === Documents.url
By handler
1. First I make a request to Counts and count the count fields
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
        }
    ])

At the output I get an array of documents of the form
[
    {
         _id: "Documents.url",
         count: 5000
    }
    //... и так 12 записей
]

The query takes a long time, there is a lot of data in the collection, an index on the createdAt field has been created, perhaps there is a faster way to get the sum of documents, maybe I'm doing something wrong?
After sampling in Counts, I create an _id array (they are also Counts.href) and make a new sampling to form documents from 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
                })
            }))
        })

Also, the question is how to simplify the construction in the promise? Maybe there is a better solution, although given that there are only 12 documents, this design works very quickly.
It will be great if you tell me something or point your finger at the mistakes, maybe in general the logic itself needs to be redone to some more correct one

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question