Need help on converting Parse-server 2.8.1 code to 4.4.0

This code is for an application where it searches user history a populate set of data. I have an issue converting the following code to support the newest parse-server. Previously it was working, but with the convention I did to support parse-server 4.4.0, it is taking too much time (more than 40-50 sec for some users).

Code I used in parse-server 2.8.1

function parseHistory(user, histories, weightUnit) {
var historyRecords = {};

console.log("Started mainPromise");
var promises = [];

_.each(histories, function(history) {
    var canProcceed = true;

    if (history.get("isBookmarked") == true && user.get("isPremium") == false && (history.get("wasDailyChallenge") == false || history.get("wasDailyChallenge") == null)) {
        canProcceed = false;
    }

    if (canProcceed) {
        var workout = history.get("workout");
        var workoutId = history.get("workout").id;

        if (!historyRecords[workoutId]) {
            historyRecords[workoutId] = {};
        }

        // Process all the results to get the score based on the workout type
        var workoutType = workout.get("resultType");
        var results = history.get("results");
        var score = 0;
        var unit = "";
        var type = null;

        _.each(results, function(result) {
            if (result.get("type") == workoutType) {
                type = workoutType;

                if (workoutType == "time") {
                    score += parseInt(result.get("value"));
                    unit = "s";
                } else if (workoutType == "weight") {
                    if (result.get("extra") == "kg") {
                        if (weightUnit == "lb") {
                            score += parseInt(parseInt(result.get("value")) * 2.20462);
                        } else {
                            score += parseInt(result.get("value"));
                        }
                    } else if (result.get("extra") == "lb") {
                        if (weightUnit == "kg") {
                            score += parseInt(parseInt(result.get("value")) * 0.453592);
                        } else {
                            score += parseInt(result.get("value"));
                        }
                    }
                    unit = weightUnit;
                } else if (workoutType == "reps") {
                    score += parseInt(result.get("value"));
                    unit = "reps";
                } else if (workoutType == "rounds_reps") {
                    score += (parseInt(result.get("value")) * workout.get("repsPerRound")) + parseInt(result.get("extra"));
                    unit = "reps";
                }
            }
        });

        if (historyRecords[workoutId]["history"]) {
            historyRecords[workoutId]["history"].push({ history: history, score: score, unit: unit, type: type });
        } else {
            historyRecords[workoutId]["history"] = [];
            historyRecords[workoutId]["history"].push({ history: history, score: score, unit: unit, type: type });
        }

        console.log("Including pointers for workout " + workout.id);
        console.log(workout.get('warmup'));
        var workoutJson = workout.toJSON();
        var promise = Parse.Promise.as();
        promise = promise.then(function() {
            console.log("Getting movements for workout " + workoutJson.objectId);

            var movementCodes = workout.get("movements").split(",");
            console.log(movementCodes.length + " movements to retrieve");

            var queryMovements = new Parse.Query(Movement);
            queryMovements.containedIn("code", movementCodes);

            return queryMovements.find({ useMasterKey: true });
        }).then(function(movements) {
            console.log("Movements found: " + movements.length);

            var movementsJSON = [];
            _.each(movements, function(movement) {
                movementsJSON.push(movement.toJSON());
            });

            var workoutMovements = workout.get("movements").split(",");

            movementsJSON.sort(function(a, b) {
                return workoutMovements.indexOf(a["code"]) - workoutMovements.indexOf(b["code"]);
            });

            workoutJson["movements"] = movementsJSON;

            var equipmentCodes = workout.get("equipments").split(",");
            console.log(equipmentCodes.length + " equipments to retrieve");
            console.log(equipmentCodes);

            if (equipmentCodes.length > 0) {
                console.log("Querying equipments");
                var queryEquipments = new Parse.Query(Equipment);
                queryEquipments.containedIn("code", equipmentCodes);

                return queryEquipments.find({ useMasterKey: true });
            } else {
                return Parse.Promise.as();
            }
        }).then(function(equipments) {
            console.log("Equipments found: " + equipments.length);

            var equipmentsJSON = [];

            _.each(equipments, function(equipment) {
                equipmentsJSON.push(equipment.toJSON());
            });

            workoutJson["equipments"] = equipmentsJSON;

            var goalCodes = workout.get("goals").split(",");
            console.log(goalCodes.length + " goals to retrieve");

            if (goalCodes.length > 0) {
                var queryGoals = new Parse.Query(Goal);
                queryGoals.containedIn("code", goalCodes);

                return queryGoals.find({ useMasterKey: true });
            } else {
                return Parse.Promise.as();
            }
        }).then(function(goals) {
            console.log("Goals found: " + goals.length);

            var goalsJSON = [];
            _.each(goals, function(goal) {
                goalsJSON.push(goal.toJSON());
            });

            workoutJson["goals"] = goalsJSON;
            workoutJson["instructions"] = workout.get('instructions').toJSON();

            var warmupMovementsJSON = [];
            _.each(workout.get('warmup').get('movements'), function(movement) {
                warmupMovementsJSON.push(movement.toJSON());
            });

            var workoutMovements = workout.get('warmup').get('movements');

            warmupMovementsJSON.sort(function(a, b) {
                return workoutMovements.indexOf(a["code"]) - workoutMovements.indexOf(b["code"]);
            });

            workoutJson["warmup"] = workout.get('warmup').toJSON();
            workoutJson["warmup"]["movements"] = warmupMovementsJSON;

            historyRecords[workoutId]["workout"] = workoutJson;

            return Parse.Promise.as();
        });

        promises.push(promise);
    }
});

return Parse.Promise.when(promises).then(function() {
    var historyArray = [];

    for (var key in historyRecords) {
        var workoutHistory = historyRecords[key];
        var latestCompletion = null;

        _.each(workoutHistory["history"], function(historyArray) {
            var history = historyArray["history"];

            if (history.get("isComplete") === true) {
                if (!latestCompletion) {
                    latestCompletion = history.updatedAt;
                } else {
                    if (moment(latestCompletion).isBefore(history.updatedAt)) {
                        latestCompletion = history.updatedAt;
                    }
                }
            }
        });

        // Set the latest completion date, if available
        if (latestCompletion) {
            workoutHistory["completion"] = latestCompletion;
        }

        historyArray.push(workoutHistory);
    }

    return Parse.Promise.as(historyArray);
}, function(error) {
    console.log(error.message);
    return Parse.Promise.as();
});

}

Converted code, which leads to 30+ slow/error response mails… for 24h time period :sob:

async function parseHistory(user, histories, weightUnit) {
var historyRecords = {};

console.log("Started mainPromise");
var promises = [];

for (var history of histories) {
    var canProcceed = true;
    if (history.get("isBookmarked") == true && user.get("isPremium") == false && (history.get("wasDailyChallenge") == false || history.get("wasDailyChallenge") == null)) {
        canProcceed = false;
    }

    if (canProcceed) {
        var workout = history.get("workout");
        var workoutId = history.get("workout").id;

        if (!historyRecords[workoutId]) {
            historyRecords[workoutId] = {};
        }

        // Process all the results to get the score based on the workout type
        var workoutType = workout.get("resultType");
        var results = history.get("results");
        var score = 0;
        var unit = "";
        var type = null;

        _.each(results, function(result) {
            if (result.get("type") == workoutType) {
                type = workoutType;

                if (workoutType == "time") {
                    score += parseInt(result.get("value"));
                    unit = "s";
                } else if (workoutType == "weight") {
                    if (result.get("extra") == "kg") {
                        if (weightUnit == "lb") {
                            score += parseInt(parseInt(result.get("value")) * 2.20462);
                        } else {
                            score += parseInt(result.get("value"));
                        }
                    } else if (result.get("extra") == "lb") {
                        if (weightUnit == "kg") {
                            score += parseInt(parseInt(result.get("value")) * 0.453592);
                        } else {
                            score += parseInt(result.get("value"));
                        }
                    }
                    unit = weightUnit;
                } else if (workoutType == "reps") {
                    score += parseInt(result.get("value"));
                    unit = "reps";
                } else if (workoutType == "rounds_reps") {
                    score += (parseInt(result.get("value")) * workout.get("repsPerRound")) + parseInt(result.get("extra"));
                    unit = "reps";
                }
            }
        })

        if (historyRecords[workoutId]["history"]) {
            historyRecords[workoutId]["history"].push({history: history, score: score, unit: unit, type: type});
        } else {
            historyRecords[workoutId]["history"] = [];
            historyRecords[workoutId]["history"].push({history: history, score: score, unit: unit, type: type});
        }

        console.log("Including pointers for workout " + workout.id);
        console.log(workout.get('warmup'));
        var workoutJson = workout.toJSON();

        console.log("Getting movements for workout " + workoutJson.objectId);

        var movementCodes = workout.get("movements").split(",");
        console.log(movementCodes.length + " movements to retrieve");

        var queryMovements = new Parse.Query(Movement);
        queryMovements.containedIn("code", movementCodes);

        var movements = await queryMovements.find({useMasterKey: true});
        console.log("Movements found: " + movements.length);

        var movementsJSON = [];
        _.each(movements, (movement) => {
            movementsJSON.push(movement.toJSON());
        });

        var workoutMovements = workout.get("movements").split(",");
        movementsJSON.sort((a, b) => {
            return workoutMovements.indexOf(a["code"]) - workoutMovements.indexOf(b["code"]);
        });

        workoutJson["movements"] = movementsJSON;

        var equipmentCodes = workout.get("equipments").split(",");
        console.log(equipmentCodes.length + " equipments to retrieve");
        console.log(equipmentCodes);

        var equipments = null;
        if (equipmentCodes.length > 0) {
            console.log("Querying equipments");
            var queryEquipments = new Parse.Query(Equipment);
            queryEquipments.containedIn("code", equipmentCodes);

            equipments = await queryEquipments.find({useMasterKey: true});
        }

        console.log("Equipments found: " + equipments.length);
        var equipmentsJSON = [];

        _.each(equipments, (equipment) => {
            equipmentsJSON.push(equipment.toJSON());
        });

        workoutJson["equipments"] = equipmentsJSON;
        var goalCodes = workout.get("goals").split(",");
        console.log(goalCodes.length + " goals to retrieve");

        var goals = null;
        if (goalCodes.length > 0) {
            var queryGoals = new Parse.Query(Goal);
            queryGoals.containedIn("code", goalCodes);

            goals = await queryGoals.find({useMasterKey: true});
        }

        console.log("Goals found: " + goals.length);
        var goalsJSON = [];
        _.each(goals, (goal) => {
            goalsJSON.push(goal.toJSON());
        });

        workoutJson["goals"] = goalsJSON;
        workoutJson["instructions"] = workout.get('instructions').toJSON();

        var warmupMovementsJSON = [];
        _.each(workout.get('warmup').get('movements'), (movement) => {
            warmupMovementsJSON.push(movement.toJSON());
        });

        var workoutMovements = workout.get('warmup').get('movements');

        warmupMovementsJSON.sort((a, b) => {
            return workoutMovements.indexOf(a["code"]) - workoutMovements.indexOf(b["code"]);
        });

        workoutJson["warmup"] = workout.get('warmup').toJSON();
        workoutJson["warmup"]["movements"] = warmupMovementsJSON;
        historyRecords[workoutId]["workout"] = workoutJson;
    }
}

var historyArray = [];

for (var key in historyRecords) {
    var workoutHistory = historyRecords[key];
    var latestCompletion = null;

    _.each(workoutHistory["history"], (historyArray) => {
        var history = historyArray["history"];

        if (history.get("isComplete") === true) {
            if (!latestCompletion) {
                latestCompletion = history.updatedAt;
            } else {
                if (moment(latestCompletion).isBefore(history.updatedAt)) {
                    latestCompletion = history.updatedAt;
                }
            }
        }
    });

    // Set the latest completion date, if available
    if (latestCompletion) {
        workoutHistory["completion"] = latestCompletion;
    }

    historyArray.push(workoutHistory);
}

return historyArray;

}

I know this is bad coding but, I have no option right now since this function is using more than 27k+ users. Please guide me…

Since you are using cloud code is directAccess: true and enableSingleSchemaCache: true set in your server config.

Also you can rewrite this to run your queries in parallel instead of serial.