0

I am trying to read a file on parse.com and using a for loop iterate over all the records present in it. On each record, I need to perform 4 operations, each dependent on the other. Can someone please guide how I can do that so that each record is processed in the for loop.

Parse.Cloud.httpRequest({
            url: urlValue
        }).then(function(fileResponse) {
            console.log("processUploadFile:httpRequest:response:" + JSON.stringify(fileResponse.buffer.length));
            // console.log("processUploadFile:Text:" + fileResponse.text);

            var records = fileResponse.text.split("\r");

            for (var i = 0; i < records.length; ++i) {
                // console.log("Record:" + i + " detail:" + records[i] + "\n\n");
                var record = records[i];


                        console.log("processUploadFile:adding patient");
                        Parse.Cloud.run("addPatient", {
                            record:record
                        }, {
                            success: function(objectId) {
                                console.log("Created objectId:" + JSON.stringify(objectId));
                                Parse.Cloud.run("addProvider", {
                                    record:record
                                }, {
                                    success: function(objectId) {
                                        console.log("Created objectId:" + JSON.stringify(objectId));

                                        Parse.Cloud.run("addLocation", {
                                            record:record
                                        }, {
                                            success: function(objectId) {
                                                console.log("objectId:" + JSON.stringify(objectId));
                                            },
                                            error: function(error) {
                                                console.log(JSON.stringify(error));
                                            }
                                        });
                                    },
                                    error: function(error) {
                                        console.log(JSON.stringify(error));
                                    }
                                });
                            },
                            error: function(error) {
                                console.log(JSON.stringify(error));
                            }
                        });
                    };
                }
            }


            response.success();
        });
i_raqz
  • 2,919
  • 10
  • 51
  • 87
  • This sort of nested-event madness is why I created www.taskrunnerjs.com - although there are lots of other alternatives. IMO those styles of chaining are much easier to read and comprehend than this. (This is just an opinion, not so much an answer. Honestly it's not entirely clear what you're asking.) – bvaughn Mar 04 '15 at 17:49
  • 1
    Do those subsequent steps depend on each other, in other words, e.g. must addPatient be completed before before addProvider can work, or may these be performed in any order? – danh Mar 04 '15 at 18:03
  • @danh... yes ... addPatient is dependent on completion of addProvider – i_raqz Mar 04 '15 at 18:24
  • @brianvaughn ... www.taskrunnerjs.com looks great... but I don't think I can use that on parse.com. Can I use promises? – i_raqz Mar 04 '15 at 18:26
  • Okay, I guessed that was the case and organized my answer to do the addPatient operations first. – danh Mar 04 '15 at 18:28
  • 1
    you can (and should) use promises with parse.com on both client and server. @brianvaughn's library looks to be well thought out, though I've never used it. – danh Mar 04 '15 at 18:30
  • FWIW, Task Runner is fully compatible with Promises. But yes, you should use Promises with parse.com. I was just pointing out an alternative style that is easier to read (and so less likely to contain hidden bugs). – bvaughn Mar 04 '15 at 18:32

1 Answers1

1

The right right answer depends on the semantics of those operations, whether they depend on each other in any way. The other part of a right right answer accounts for transaction rate limits and timeouts imposed by parse.com. That also depends on what happens in the cloud operations and how much data is being processed.

But the right answer (as opposed to right right) is to perform operations serially by chaining promises' then(), and to perform groups of operations concurrently (or in arbitrary order) with Parse.Promise.when().

One such ordering would look like this:

var patientQs = [];
var providerQs = [];
var locationQs = [];
var records;

Parse.Cloud.httpRequest({url: urlValue}).then(function(fileResponse) {
    console.log("processUploadFile:httpRequest:response:" + JSON.stringify(fileResponse.buffer.length));
    records = fileResponse.text.split("\r");
    for (var i = 0; i < records.length; ++i) {
        // console.log("Record:" + i + " detail:" + records[i] + "\n\n");
        var record = records[i];
        patientQs.push(Parse.Cloud.run("addPatient", {record:record}));
        providerQs.push(Parse.Cloud.run("addProvider", {record:record}));
        locationQs.push(Parse.Cloud.run("addLocation", {record:record}));
    }
    return Parse.Promise.when(patientQs);
}).then(function() {
    // since the result of addPatient is an objectId, arguments
    // will be the corresponding objectIds for each run 
    for (var i=0; i<arguments.length; i++) {
        console.log(arguments[i] + " is the object id for input record " + JSON.stringify(records[i]));
    }
    return Parse.Promise.when(providerQs);
}).then(function() {
    return Parse.Promise.when(locationQs);
}).then(function() {
    response.success();
}, function(error) {
    response.error(error);
});

This says, "go thru the http-retrieved records, and first add all of the patients for those records, then add all of the providers, and so on".

Or, you could group the operations by input record, like this:

Parse.Cloud.httpRequest({url: urlValue}).then(function(fileResponse) {
    console.log("processUploadFile:httpRequest:response:" + JSON.stringify(fileResponse.buffer.length));
    var records = fileResponse.text.split("\r");
    var recordQs = [];

    for (var i = 0; i < records.length; ++i) {
        // console.log("Record:" + i + " detail:" + records[i] + "\n\n");
        var record = records[i];
        recordQs.push(processARecord(record));
    }
    return Parse.Promise.when(recordQs);
}).then(function() {
    response.success(arguments);
}, function(error) {
    response.error(error);
});

function processARecord(record) {
    var result = {};
    return Parse.Cloud.run("addPatient", {record:record}).then(function(objectId) {
        console.log(objectId + " is the object id for input record " + JSON.stringify(record));
        result.patientId = objectId;
        return Parse.Cloud.run("addProvider", {record:record});
    }).then(function (providerId) {
        result.providerId = providerId;
        return Parse.Cloud.run("addLocation", {record:record});
    }).then(function(locationId) {
        result.locationId = locationId;
        return result;
    });
}
danh
  • 62,181
  • 10
  • 95
  • 136
  • this is something close to what I was looking for. I didnt know, we could add those many "then" blocks... How do we a return a value from the block though. after the addPatient completes, I need the objectId of the currently added patient. – i_raqz Mar 04 '15 at 19:00
  • also, can't we perform addpatient, then addProvider then addLocation for the same record then move on to the next record? – i_raqz Mar 04 '15 at 19:00
  • @i_raqz - re the first comment: see edit. var args to the then() will contain objects corresponding to each fulfilled promise. re your second comment: yes, this is easily done by making a chain of promises for each record, rather than a group for each function type. – danh Mar 04 '15 at 19:09
  • @i_raqz - regrouped to illustrate point about grouping by input rather than by function. The bigger point is that chaining then()'s gives you sequence and performing when()'s gives you semi-concurrence. – danh Mar 04 '15 at 19:15
  • this is exactly what i was looking for..you gave a me a little tutorial about using Promise as well async calls. – i_raqz Mar 04 '15 at 19:21
  • just one last thing... can we return the patientObjectId, locationOBjectId and providerObjectId to one method so that an operation can be perform on all three. – i_raqz Mar 04 '15 at 19:23
  • yes indeed. see edit. note that success() passes the arguments back to the caller, which will be an array of the result objects from that processRecord function { patientId: "foo", "providerId:"bar", locationId:"baz"} – danh Mar 04 '15 at 19:26
  • this is great @danh... thank you! makes total sense to me now – i_raqz Mar 04 '15 at 19:50
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72280/discussion-between-i-raqz-and-danh). – i_raqz Mar 04 '15 at 22:44