Search code examples
javascriptjsonparse-platformpromiseparse-cloud-code

Issues with Parse Cloud Code Promises


I am trying to work with Parse Cloud Code and use promises to make sure I eliminate any issues with cals being async. I am wanting to query a class, get an object back, build up some JSON, then query some relations of the object (tags, referees) and add them to the JSON to return back for ExpressJS to render. The code I paste is not working but I don't understand why if each time I am returning to project for the next promise to query on.

Edit:

//Return a single project
Parse.Cloud.define('getProject', function(request, response) {
    var projectUrl = request.params.projectUrl;

    var project;
    var projectsData = [];

    var Projects = new Parse.Object("projects");
    var query = new Parse.Query(Projects);
    query.equalTo("projectUrl", projectUrl);
    query.find().then(function(projectsResult) {
        console.log(projectsResult.length + " Projects returned");

        project = projectsResult[0];
        var projectData = {
            "id": project.get("id"),
            "title": project.get("title"),
            "previewImage": project.get("previewImage"),
            "longDescription": project.get("longDescription"),
            "shortDescription": project.get("shortDescription"),
            "visibleToPublic": project.get("visibleToPublic"),
            "dateStart": project.get("dateStart"),
            "dateEnd": project.get("dateEnd"),
            updatedAt: project.get("updatedAt"),
            projectStatus: project.get("projectStatus")
        };

        projectsData.push(projectData);
        console.log("Step 1. Projects Data: " + JSON.stringify(projectsData));

        var tagsQuery = project.relation('tags');
        return tagsQuery.query().find();
    }).then(function(tags) {
        var tagsData = [];
        for(var t = 0; t < tags.length; t++) {
            var tagData = {
                "tag": tags[t].get("tag"),
            }
            console.log("Tag Data: " + tagData);
            tagsData.push(tagData);
        }
        projectsData[tags] = tagsData;
        console.log("Step 2. Tags Data: " + JSON.stringify(tagsData));

        var refereesQuery = project.relation('referees');
        return refereesQuery.query().find();
    }).then(function(referees) {
        var refereesData = [];
        for(var r = 0; r < referees.length; r++) {
            var refereeData = {
                "name": referees[r].get("name"),
                "role": referees[r].get("role"),
                "emailAddress": referees[r].get("emailAddress"),
                "phoneNumber": referees[r].get("phoneNumber"),
                "linkedInUrl": referees[r].get("linkedInUrl"),
            }
            console.log("Referee Data: " + refereeData);
            refereesData.push(refereeData);
        }
        projectsData[referees] = refereesData;
        console.log("Step 3. Referees Data: " + JSON.stringify(refereesData));

        console.log("Everthing should be part of Projects Data here: " + JSON.stringify(projectsData));

        response.success(projectsData);
    }, function(error) {
        response.error("Error: " + error);
    });
});

Solution

  • There are several issues :

    • Confusion between projectsData and projectData
    • projectsData isn't actually necessary.
    • projectData needs to be in scope in the three places it is (or should be) used after it is created & assigned.
    • In several cases .then() is used where standard synchronous flow will suffice. Purging the unnecessary .thens will help greatly in sorting out the scope issues.

    Doing little more than shuffling the code around, I arrive at the following :

    Parse.Cloud.define('getProject', function(request, response) {
        var Projects = Parse.Object.extend("projects"); // with credit to @kRiZ
        var query = new Parse.Query(Projects);
        query.equalTo('projectUrl', request.params.projectUrl);
        query.find().then(function(projectsResult) {
            var project = projectsResult[0];
            var projectData = {
                'id': project.get('id'),
                'title': project.get('title'),
                'previewImage': project.get('previewImage'),
                'longDescription': project.get('longDescription'),
                'shortDescription': project.get('shortDescription'),
                'visibleToPublic': project.get('visibleToPublic'),
                'dateStart': project.get('dateStart'),
                'dateEnd': project.get('dateEnd'),
                'updatedAt': project.get('updatedAt'),
                'projectStatus': project.get('projectStatus')
            };
    
            //Now make the tags query and the referees query in parallel.
            var tagsPromise = project.relation('tags').query().find();
            var refereesPromise = project.relation('referees').query().find();
    
            // Aggregate the two promises with Parse.Promise.when(), and handle the responses.
            return Parse.Promise.when(tagsPromise, refereesPromise).then(function(tags, referees) {
                //Process the tags response
                projectData.tags = tags.map(function(t) {
                    return {
                        'tag': t.get('tag')
                    };
                });
                //Process the referees response
                projectData.referees = referees.map(function(r) {
                    return {
                        'name': r.get('name'),
                        'role': r.get('role'),
                        'emailAddress': r.get('emailAddress'),
                        'phoneNumber': r.get('phoneNumber'),
                        'linkedInUrl': r.get('linkedInUrl')
                    };
                });
                // Yay!
                response.success(projectData);
            });
        }).fail(function(error) {
            response.error('Error: ' + error);
        });
    });
    

    Apart from the overall rearrangement, the only substantial changes are :

    • Using Array#map() to map an array to another array.
    • Making two queries in parallel and using Parse.Promise.when() to aggregate the two promises.