josealvarado111
josealvarado111

Reputation: 575

Parse Cloud Code - How to query the User Class

I'm trying to query the Parse User Class but I'm not getting any results. The User class has a column labeled "phone", and I'm passing an array of dictionaries where each dictionary has a key "phone_numbers" that corresponds to an array of phone numbers. I'm trying to determine if a User in my table has one of those phone numbers. I'm not getting any errors running the code, but there does exist a user in my table with a matching phone number. What am I doing wrong?

Parse.Cloud.define("hasApp", function(request, response) {
    var dict = request.params.contacts;
    var num = 0;
    var found = 0;
    var error = 0;
    var phoneNumbers = "";
    for (var i = 0; i < dict.length; i++){
        var result = dict[i].phone_numbers;
        num += result.length;
        for (var j = 0; j < result.length; j++){
            phoneNumbers += result[j] + ", ";

            var query = new Parse.Query(Parse.User);

            query.equalTo("phone", result[j]);
            query.find({
              success: function(results) {
              found = 1;
          },
          error: function() {
            error = 1;
          }
          });
        }
    }
    response.success("hasApp " + dict.length + " numbers " + num + " found " + found + " error " + error + " phoneNumbers " + phoneNumbers);
});

My response from calling this is

hasApp 337 numbers 352 found 0 error 0 phoneNumbers "list of phone numbers" 

where some of those phone numbers appear in my User class. As far as I can tell I'm not getting any errors but I'm also not successfully querying the User table

UPDATE

After moving

response.success("hasApp " + dict.length + " numbers " + num + " found " + found + " error " + error + " phoneNumbers " + phoneNumbers);

to the body of the success block, I get the following error because I'm only allowed to call response.success once per cloud function.

Error Domain=Parse Code=141 "The operation couldn’t be completed. (Parse error 141.)"     
UserInfo=0x14d035e0 {code=141, error=Error: Can't call success/error multiple times
    at Object.success (<anonymous>:99:13)
    at query.find.success (main.js:44:12)
    at Parse.js:2:5786
    at r (Parse.js:2:4981)
    at Parse.js:2:4531
    at Array.forEach (native)
    at Object.w.each.w.forEach [as _arrayEach] (Parse.js:1:666)
    at n.extend.resolve (Parse.js:2:4482)
    at r (Parse.js:2:5117)
    at Parse.js:2:4531}

Does this mean that I'm only able to verify one phone number at a time? So I can't pass an array of phone numbers and get the PFUser objects corresponding to those phone numbers (if they exist)?

I understand that my internal query to Parse.User is happening synchronously with my "hasApp" call, so is there a way to query Parse.User asynchronously? That way I can respond back to the client after checking all the phone numbers?

Upvotes: 1

Views: 2176

Answers (4)

Joel
Joel

Reputation: 838

Querying a Parse.User is fairly easy and well explained in the documentation, here is an example taken from it

var query = new Parse.Query(Parse.User);
query.equalTo("gender", "female");  // find all the women
query.find({
  success: function(women) {
    // Do stuff
  }
});

For your case it will be something like this:

Parse.Cloud.define("getAllFemales", function(request, response) {
  var query = new Parse.Query(Parse.User);
    query.equalTo("gender", "female");  // find all the women
    query.find({
      success: function(women) {
        // Do stuff
      }
    });
});

Hope it helps, as always more info on the Documentation

Upvotes: 0

rob
rob

Reputation: 156

You can use Parse.Promise to solve logic where you need to iterate through O(n) number of database queries in one asynchronous Cloud Code definition:

var _ = require("underscore"),
    isEmpty = function (o) { // standard function to check for empty objects
        if (o == null) return true;
        if (o.length > 0)    return false;
        if (o.length === 0)  return true;
        for (var p in o) {
            if (hasOwnProperty.call(o, p)) return false;
        }
        return true;
    };

Parse.Cloud.define("hasApp", function (request, response) {
    var dict = request.params.contacts,
        users = [];

    var promise = Parse.Promise.as();
    _.each(dict, function (obj) {
        _.each(obj.phone_numbers, function (num) {
            promise = promise.then(function () {
                var promiseQuery = new Parse.Query(Parse.User);
                promiseQuery.equalTo("phone", parseInt(num));
                return promiseQuery.find({
                    success: function (result) {
                        if (isEmpty(result)) // don't save empty results e.g., "[]"
                            return;
                        users.push(result); // save results to a model to prevent losing it in scope
                    }
                });
            });
        });
    });
    return promise.then(function () {
        response.success("Found user(s): " + JSON.stringify(users));
    });

});

Note a few things about this block:

  • You can append functionality iteratively to a Parse.Promise.
  • You can loose scope of database results in your iteration. Use a local array model to save your query results to. Although, I presume there is a better way to achieve the same functionality without the use of a user model, someone else can quote me on that.
  • Pay close attention to the way Parse handles data. For example, if you are storing your phone numbers as numbers, you have to make sure you use parseInt() when querying for it.

Be aware that you must attach your response.success() function to your promise to assure it is resolved after your iterations have run. From this block, your response from Parse will look similar to an array of User objects. You can decide on the many different ways you can save the data model depending on what you need it for.

As a final note, this block doesn't account for any validation or error handling that should be accounted for otherwise.

Upvotes: 4

boinged
boinged

Reputation: 533

You're now calling response.success in a loop now. You should only call response.success/response.error once per cloud function.

It would help if you can show the original code with no commented out lines (to show your original intention) and the new code with no commented out lines as two separate code samples.

Upvotes: 0

BHendricks
BHendricks

Reputation: 4493

The problem seems to be that your response.success call is happening before the query can even happen. While you have response.success calls in your query success block, they are never called because you return success before the query is executed.

Try commenting out the line:

response.success("hasApp " + dict.length + " numbers " + num + " found " + found + " error " + error + " phoneNumbers " + phoneNumbers);

This should let the code go to your query, and maybe move it into the success block of your query.

Let me know if this works.

Upvotes: 0

Related Questions