简体   繁体   中英

How can I optimize the speed of this algorithm? Django and Javascript

I am new to Javascript and have decent experience with Django. I built a charting platform for my company to track metrics -- it started as a hobby project to learn Javascript but evolved into something more.

The site loads and displays data correctly, but it is unbelievably slow on mobile. All of the calculations are being done on the client-side is JS. There are a lot of metrics to calculate, so the thought process was "Send the client all the Django queries in Object format, and process them there in order to not slow down the server." I also did not want to have a huge block of code processing each metric on the server (am I wrong to do this?).

Some questions here:

  • In general, where should I process the data, server-side or client-side?
  • How can I optimize this code? I run 3 queries, and I need to find the number of hits for each metric on every day (page views, opt-ins, and scheduled calls).

For example, I want to display a chart showing the number of page views over a month period with the x-axis being the date, and the y-axis being count. In order to do this, I run a nested for loop to iterate over the query, then to count the number of page views for that date.

This is extremely slow when I run this function for three different metrics.

The data is received in an ajax call (is this optimal?). Here is the Javascript code that counts the number of hits for that day:

var endpoint = "/my/url/";
        var opt_ins = [];
        var schedules = [];
        var page_views = [];
        $.ajax({
            method: "GET",
            url: endpoint,
            success: function (data) {
                opt_ins = data.opt_ins;
                schedules = data.audit_calls;
                page_views = data.page_views;
            },
            error: function (error) { console.log("ERROR -->  " + error); },
            async: false
        });


async function getDateCounts(data) {
            dates = [];
            count_dates = [];
            let i = 0;
            for (const element of data) {
                let date = new Date(element.date_created).toLocaleDateString("en-US");
                if (!dates.includes(date)) {
                    dates.push(date);
                    let count = 0;
                    for (const item of data) {
                        let check_date = new Date(item.date_created).toLocaleDateString("en-US");
                        if (check_date === date) {
                            count++;
                        }
                    }
                    count_dates.push(count);
                    count = 0;
                }
            }
            return [dates, count_dates];

Here is the Django view:

class ChartData(APIView):
    authentication_classes = []
    permission_classes = []
    now = pendulum.now()
    time_period = now.subtract(months=1)

    def get(self, request, format=None):
        page_views = (
            models.AgentPageViews.objects.filter(date_created__gt=self.time_period)
            .order_by("date_created")
            .values()
        )
        opt_ins = (
            models.Client.objects.filter(date_created__gte=self.time_period)
            .order_by("date_created")
            .values()
        )
        audit_calls = (
            models.ScheduledCalls.objects.filter(date_created__gte=self.time_period)
            .filter(event__contains="Audit")
            .order_by("date_created")
            .values()
        )

        data = {
            "page_views": list(page_views),
            "opt_ins": list(opt_ins),
            "audit_calls": list(audit_calls),
        }

        return Response(data)

Each of these queries returns an object of a different length.

Here is an example of what the final chart looks like with sample data

The database is a great place to aggregate this data and will reduce the amount of data needed to be passed around.

The aggregate() method will let you get a data set like:

[{'date':COUNT},{'date':COUNT},...]

TruncDate() allows group by day if you have a datetime.

from django.db.models import Sum
from django.db.models.functions import TruncDate


models.AgentPageViews.objects.filter(date_created__gt=self.time_period).
    values(date=TruncDate('date_created')).
    order_by("date_created").annotate(Sum('views')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM