0

I am attempting to write a Parse Cloud Code function where the parameter is a list of Objects that each include a geoPoint member. For each item in the list, I will search the Parse data store for an existing item in a 1 mile radius with the same name. If the item does not exist, then create the item and save it to the data store.

My Function

/**
 *  Take a list of Place and check for existence in Parse.
 *  If it doesn't already exist, add it.
 *  @see https://www.parse.com/questions/access-distance-on-a-geoquery
 *  @param {JSON Place.PlaceSearch}
 *  @return none
 */
 function addConvertedApiResult(placeData) {
    for ( var i = 0; i < placeData.length; i++ ) {
        // look near loc for existing name
        var loc = new Parse.GeoPoint(placeData[i].lat, placeData[i].lon)

        var query = new Parse.Query("Place");
        query.withinMiles("location", loc, 1);
        query.equalTo("name", placeData[i].name);

        console.log("placeData[i].name:"+placeData[i].name);
        query.find({
            success: function(results) {
                // results contains a list of places that are within 1 mile
                // and have the same name
                console.log("results.length = "+results.length);
                if(results.length < 1) {
                    // add the place
                    var Place = Parse.Object.extend("Place");
                    var place = new Place();

                    place.set("en", placeData[i].name);
                    place.set("location", loc);
                    place.set("moreInfo", placeData[i].moreInfo);

                    place.save();
                }
            },
            error: function(error) {
                // There was an error.
                console.log("error = "+error.message);
            }
        });

        console.log("leaving addConvertedApiResult");
    }
}

My request to a Cloud Function that calls addConvertedApiResult

(Must escape '"' from windows command line)

curl -X POST 
-H "X-Parse-Application-Id: <key>" 
-H "X-Parse-REST-API-Key: <key>" -H "Content-Type: application/json" 
-d "{\"name\":\"Storm+Mountain\",\"lat\":44.0760,\"lon\":-103.2280,\"limit\":5,\"radius\":25}" https://api.parse.com/1/functions/getPlace
{"result":[{"lat":43.95483,"lon":-103.36869,"moreInfo":"<apiUrl>/item.php?c=1\u0026i=3439","name":"Storm Mountain"}]}

Resulting Parse Info Log

I2015-03-03T05:56:26.905Z] v99: Ran cloud function getPlace with:
  Input: {"lat":44.0760,"limit":5,"lon":-103.2280,"name":"Storm+Mountain","radius":25}
  Result: [{"name":"Storm Mountain","lat":43.95483,"lon":-103.36869,"moreInfo":"<moreInfoUrl>"}]

I2015-03-03T05:56:27.434Z] placeData[i].name:Storm Mountain

I2015-03-03T05:56:27.435Z] leaving addConvertedApiResult

There are 4 existing points in the data store that should be returned but none of them share the same name. The function does not seem to execute the query.find method. I do not see the log messages from the success: or error: functions. If I understand correctly, these functions should allow me to execute code on the query results.

How could I confirm there are no results from the query if console.log does not seem to work?

I've been up and down the web trying different variations on this syntax. Is my syntax correct?

Thanks.

Update

I've been working on this problem again and was excited to learn about Promises. Unfortunately, my situation has not changed. I am now calling these functions from my addConvertedApiResult function. I've tested/debugged them with a driver written in a local javascript file using Chrome Developer tools, everything runs nicely. But, when I deploy this code to Parse Cloud Code execution seems to disappear into the ether after I call .find().

I understand that code execution is asynchronous on CC but I'm under the impression that the use of the .then() function should overcome that limitation.

I hope someone can explain to me what I'm missing.

Thanks.

/**
 *  Take a Place and check for existence in Parse.
 *  If it doesn't already exist, add it.
 *  @see https://www.parse.com/questions/access-distance-on-a-geoquery
 *  @see https://parse.com/docs/js_guide#promises-chaining
 *  @param {JSON Place.PlaceSearch}
 *  @return none
 */
function addNewPlace(place) {
    // look near loc for already existing place with same name
    var loc = new Parse.GeoPoint(place.lat, place.lon)
    var query = new Parse.Query('Place');
    query.withinMiles('location', loc, 1);
    query.equalTo('en', place.name);
    query.find().then( function(results) {
        if(results.length < 1) {
            console.log(place.name+" does not exist")
            var Place = Parse.Object.extend("Place");
            var newPlace = new Place();

            var loc = new Parse.GeoPoint(place.lat, place.lon)
            newPlace.set('en', place.name);
            newPlace.set('location', loc);
            newPlace.set('moreinfo', place.moreinfo);

            return newPlace.save();
        }
    });
}

/**
 *  Take a list of Place and check for existence in Parse.
 *  If it doesn't already exist, add it.
 *  @see https://www.parse.com/questions/access-distance-on-a-geoquery
 *  @see https://parse.com/docs/js_guide#promises-chaining
 *  @param {JSON Place.PlaceSearch}
 *  @return none
 */
function addConvertedApiResult(placeData) {
    var _ = require('underscore');

    console.log("placeData.legth:"+placeData.length);
    _.each(placeData, function(place) {
        addNewPlace(place);
    });
}
Chad
  • 3
  • 3
  • Try to use debugger (Ctrl+Shift+J in Chrome -> Source tab). Just place breakpoint at the `query.find` line and update the page (or click a button, I do not know when your code should be runned, actually). – Anatoliy Arkhipov Mar 03 '15 at 07:11
  • Thank you for the comment. This code runs on the Parse Service not in my browser, but you bring up a good point. Maybe I should have asked, "How should I debug javascript being deployed to Parse Cloud Code?". – Chad Mar 03 '15 at 15:36
  • The code snippets I provided above are syntactically correct. My problem though, was that it took me awhile to get my head wrapped around the concept of programming sequential asynchronous calls to Parse and other APIs from CloudCode. Ultimately I was able to accomplish what I wanted using one single function with a string of promises using the following pattern. – Chad Mar 16 '15 at 20:28

1 Answers1

0

The code snippets I provided above are syntactically correct. My problem though, was that it took me awhile to get my head wrapped around the concept of programming sequential asynchronous calls to Parse and other APIs from CloudCode. Ultimately I was able to accomplish what I wanted using one single function with a string of promises using the following pattern.

someCall( function(someObject) {
    // do some stuff
    return result;

}).then( function(resultOfPrev) {
    // do some more stuff
    return result;

}).then( function(resultOfPrev) {
    // create some nested promises

    // Create a trivial resolved promise as a base case.
    var queryPromise = Parse.Promise.as();

    _.each(resultsOfPrev, function(thing) {
        // For each item, extend the promise with a function to ...
        queryPromise = queryPromise.then( function() {

            var query = new Parse.Query(Thing);
            query.equalTo("name", thing.name);

            return query.find().then( function(result) {

                var savePromise = Parse.Promise.as();
                savePromise = savePromise.then( function() {

                    var saved = false;
                    if(result.length < 1) {
                        // then save the thing
                        var newThing =  new Thing();
                        newThing.set('name', thing.name);
                        return newThing.save();
                    } else {
                        return false;
                    }
                });

                return savePromise;
            });
        });
    });

    return queryPromise;

}).then( function(resultsOfPrev) {
    // response must not be called until
    // the end of the chain.
    response.success( resultsOfPrev);

}.then( function() {
    // i realy don't understand why but,
    // I need this empty function at the 
    // tail of the chain.
});
Chad
  • 3
  • 3