Skip to content

Cloud code not working after migration #2355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
TheMikeCannell opened this issue Jul 20, 2016 · 24 comments
Closed

Cloud code not working after migration #2355

TheMikeCannell opened this issue Jul 20, 2016 · 24 comments
Labels
type:question Support or code-level question

Comments

@TheMikeCannell
Copy link

After migration we thought we had everything up and running but then realized that we were receiving erroneous responses from the server (AWS). We are sending latitude and longitude as params when we call PFCloud in iOS, like so:

NSDictionary *params = @{
                       @"latitude" : [NSNumber numberWithDouble:(double)self.location.coordinate.latitude],
                       @"longitude" : [NSNumber numberWithDouble:(double)self.location.coordinate.longitude]
                             };
[PFCloud callFunctionInBackground:@"myQuery" withParameters:params block:^(NSArray *response, NSError *error) {
...
}];

and then in cloud code we access it like so:

var latitude = request.params.latitude;
var longitude = request.params.longitude;

This worked perfectly on parse.com but since the move to AWS and parse server, it doesn't work. I wrapped each request in parseFloat() thinking it might fix it but it didn't.

It works again if I hardcode a latitude and longitude in the cloud code. So what is the issue with sending this a params to the cloud code with the hosted parse server?

Expected Results

The script should return a query limited by latitude and longitude.

Actual Outcome

The script disregards lat and long and returns everything

Environment Setup

  • Server
    • parse-server version: latest as of last month
    • Localhost or remote server? (AWS, Heroku, Azure, Digital Ocean, etc): AWS
  • Database
    • MongoDB version: latest as of last month
    • Localhost or remote server? (AWS, mLab, ObjectRocket, Digital Ocean, etc): mLab
@bohemima
Copy link
Contributor

What's the error? What's the output of console.logging(request.params)?

@TheMikeCannell
Copy link
Author

TheMikeCannell commented Jul 21, 2016

I get no error. console.log doesn't print out anywhere in the dashboard logs, which is a separate issue: #2244

@hramos
Copy link
Contributor

hramos commented Jul 21, 2016

@ArchonLight can you try making the request to this cloud function using the REST API? This is in order to isolate this from any issues in the Parse SDK you were using to make the Cloud function call. You will also want to make sure to log the contents of request.params within your Cloud function in order to determine how the input is being delivered as compared to what you were expecting.

In summary, I recommend doing a bit more investigation in order to distill this into an actionable issue that can be addressed in either Parse Server or the SDK you are using.

@TheMikeCannell
Copy link
Author

This request:

curl -X POST \
  -H "X-Parse-Application-Id: xxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Parse-REST-API-Key: xxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "latitude": "23.1319444" , "longitude" : "-82.3641667" , "limit" : "5" , "skip" : "0" , "objectIds" : "mzITFRYJjy,0b4xzdH9v7,0qFHdK6yIX" }' \
  http:/xxxxxxxxx.elasticbeanstalk.com/parse/functions/queryXxxXxxxxxxxXxxxxxx

Is logged as:

2016-07-21T17:06:13.845Z - POST /parse/functions/queryXxxxXxxxxXxxx { host: 'xxxxxxxxxxxx.elasticbeanstalk.com',
  'x-real-ip': 'xxx.xxx.xxx.xxx',
  'x-forwarded-for': 'xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx',
  'content-length': '108',
  accept: '*/*',
  'content-type': 'application/json',
  'user-agent': 'curl/7.43.0',
  'x-parse-application-id': 'xxxxxxxxxxxxxxxxxxxxxxxxxxx',
  'x-parse-rest-api-key': 'xxxxxxxxxxxxxxxxxxxxxxxxxxx',
  'x-forwarded-port': '80',
  'x-forwarded-proto': 'http' } {
  "latitude": "23.1319444",
  "longitude": "-82.3641667",
  "limit": "5",
  "skip": "0",
  "objectIds": "mzITFRYJjy,0b4xzdH9v7,0qFHdK6yIX"
}

And returns:
Objects that are not limited to the specified latitude and longitude. for instance:

...
"content":"Rincon","latitude":18.338371,"longitude":-67.251679,"createdAt":"2016-04-18T16:58:32.491Z","updatedAt":"2016-04-18T16:58:32.491Z",
...

The Javascript sets the query using an equalTo:

var myQuery = new Parse.Query("Activity");
myQuery.equalTo('type', "add");
myQuery.equalTo("latitude",request.params.latitude);
myQuery.equalTo("longitude",request.params.longitude);

myQuery.find().then(function (objects) {
...
}

I wrapped the requests in parseFloat(request.params.latitude) --> no difference

if I hardcode the values it works as expected and how it used to work on parse.com

myQuery.equalTo("latitude",23.1319444);
myQuery.equalTo("longitude",-82.3641667);

As I stated above, console.log doesn't work anymore. On parse.com it would output just fine.

@hramos
Copy link
Contributor

hramos commented Jul 21, 2016

This seems to be working as expected. The objects in the Parse database store the latitude and longitude as a float. Your query is using an equalTo constraint on latitude and longitude to find an exact match. When you use parseFloat to convert your strings into floats, you're not guaranteed to get the same precision as what is present in the database.

If you use one of the geoqueries to find objects with a GeoPoint within N miles of a given lat/long pair, you would not need to worry about matching the precision used here.

The fact that this used to work on Parse.com may be a lucky coincidence but I wouldn't rely on it as equality comparisons between floats is not a good practice.

@TheMikeCannell
Copy link
Author

TheMikeCannell commented Jul 21, 2016

We aren't using parseFloat() in the javascript. I only mentioned that I tried that to rule it out as a solution.

It is a coincidence that this has worked for over a year on parse.com and now on an AWS-hosted parse server it doesn't work?

I completely understand what you mean about "within N miles" but this could cause trouble in other areas. Also, this would require restructuring a live database and after migration, the older versions of the app just break

I also don't understand why it works perfectly if I type the lat and long values in the javascript, but if I pass them in from iOS, they fail.

This does not work:

var myQuery = new Parse.Query("Activity");
myQuery.equalTo('type', "add");
myQuery.equalTo("latitude",request.params.latitude);
myQuery.equalTo("longitude",request.params.longitude);

myQuery.find().then(function (objects) {
...
}

This works:

var myQuery = new Parse.Query("Activity");
myQuery.equalTo('type', "add");
myQuery.equalTo("latitude",23.1319444);
myQuery.equalTo("longitude",-82.3641667);

myQuery.find().then(function (objects) {
...
}

Either way, the lat and long is set as equalTo before the query.

@hramos
Copy link
Contributor

hramos commented Jul 21, 2016

The two queries you used as examples are not using the same sets of constraints as their parameters are not equivalent. request.params.latitude and request.params.longitude are both strings ("23.1319444" and "-82.3641667" as your logs can show), while 23.1319444 and -82.3641667 are both floating point numbers. They are not the same type. So it is not unreasonable that using two different values in this query returns different results.

If latitude and longitude are both number fields, then you must compare them against a number as well. It may be the case that the SDK here converts the string into a number using parseFloat internally, in which case you would run into the issue I highlighted earlier.

The fact that this worked in parse.com is just a lucky coincidence. This type of query should really be using a geoquery constraint, as using equalTo on a floating point number field is not a great approach.

If going down that route is not possible, consider adding two string columns to your app with the same values as the current latitude and longitude fields, and then use equalTo constraints against those columns, as you can be reasonably sure that comparing two identical strings should work as expected.

@TheMikeCannell
Copy link
Author

I agree that geoquery is a much better approach but I am coming into the project after it has been written and at this point changing to that may not be the best strategy at this point. Maybe if we fix this first we can then convert to the geoquery and then have support for all versions.

Thanks for the response, it makes more sense now as to what is going on. Still it is very frustrating with all of the blockers we have faced going from parse.com to parse server.

@hramos
Copy link
Contributor

hramos commented Jul 21, 2016

Hopefully this helps you come up with a plan to migrate over. I'll go ahead and close this out as it is not an actionable issue in Parse Server.

You may use Server Fault for questions about managing Parse Server.

For code-level and/or implementation-related questions or technical support, please refer to Stack Overflow.

@hramos hramos closed this as completed Jul 21, 2016
@TheMikeCannell
Copy link
Author

TheMikeCannell commented Jul 25, 2016

Unfortunately after going through and creating a column of strings, changing the cloud code to compare strings and sending up the lat and long as strings didn't work. I get the EXACT same results.

I think what is happening is that request.params.latitude is null, I have no idea why. The log prints out the parameters that I am sending when I call the method. However, when I try to use them in the code, they are null. I used an IF STATEMENT to check null and lat and long is null.

Again, on parse.com I didn't have this problem with the exact same code.

Parse.Cloud.define("xxxxxXxxXxxxXxxxxxx", function(request, response) {
        var latitude = request.params.latitude;
        var longitude = request.params.longitude;
}

@hramos hramos reopened this Jul 26, 2016
@hramos
Copy link
Contributor

hramos commented Jul 26, 2016

Can you post the specific Parse Server version you're using? Your original post says "latest" but it's good to be specific just so that we're on the same page.

According to your earlier comment, the request did show that latitude and longitude were both being sent to the server as part of the request, now I'd like to confirm that they are indeed being parsed and passed into the function through request.params. The easiest way to do this would probably be to use the following function:

Parse.Cloud.define("verifyParams", function(request, response) {
  response.success(request.params);
}

If all is set up correctly, you should see a json response with your latitude and longitude values listed.

@TheMikeCannell
Copy link
Author

TheMikeCannell commented Jul 26, 2016

My package.json says
"parse-server": "~2.2.12",

EDIT: I just changed the json and redeployed. No change
"parse-server": "latest",

The sent params

NSDictionary *params = @{
                             @"objectIds" : @"mzITFRYJjy,0b4xzdH9v7,0qFHdK6yIX",
                             @"limit" : [NSString stringWithFormat:@"%d",100],
                             @"skip" : [NSString stringWithFormat:@"%d",0],
                             @"latitude" : [NSNumber numberWithDouble:(double)23.1319444],
                             @"longitude" : [NSNumber numberWithDouble:(double)-82.3641667]
                             };

And received

{
    latitude = "23.1319444";
    limit = 100;
    longitude = "-82.3641667";
    objectIds = "mzITFRYJjy,0b4xzdH9v7,0qFHdK6yIX";
    skip = 0;
}

(I do notice that the lat and long were returned as strings)

in my code if I do

var latitude = request.params.latitude;

if(latitude){
   myQuery.equalTo('latitude',latitude);
}

The equalTo is never set because the IF STATEMENT fails. This is true whether I use the Number columns for latitude & longitude or the String columns for latitudeString & longitudeString. If I hardcode the equalTo and remove the IF STATEMENT, everything works for that lat & long. And thank you for reopening the issue and helping.

@hramos
Copy link
Contributor

hramos commented Jul 26, 2016

So the Cloud function is receiving the params correctly. The remaining issue here is that they are being sent as strings and not numbers, which is a client-side issue. How are you calling this cloud function?

@TheMikeCannell
Copy link
Author

TheMikeCannell commented Jul 26, 2016

NSDictionary *params = @{
                             @"objectIds" : objectIds,
                             @"limit" : [NSString stringWithFormat:@"%d",limit],
                             @"skip" : [NSString stringWithFormat:@"%d",skip],
                             @"latitude" : [NSNumber numberWithDouble:(double)self.location.coordinate.latitude],
                             @"longitude" : [NSNumber numberWithDouble:(double)self.location.coordinate.longitude]
                             };
[PFCloud callFunctionInBackground:@"myQuery" withParameters:params block:^(NSArray *response, NSError *error) {
...
}];

I use an if statement because sometimes I send lat & long to this method and sometimes I don't.

var latitude = request.params.latitude;

if(latitude){
   myQuery.equalTo('latitude',latitude);
}

Another very confusing thing that is happening is that if I just throw this in

if(latitude){
     response.success(request.params);
}

The method stops and just returns all of the params. So it is finding a value for latitude.. the IF STATEMENT is true.

However, this fails as if the IF STATEMENT fails:

if(latitude){
     myQuery.equalTo('latitude',23.1319444);
}

if(longitude){
     myQuery.equalTo('longitude',-82.3641667);
}

But commenting out the IF STATEMENTS, it works perfectly :

//if(latitude){
     myQuery.equalTo('latitude',23.1319444);
//}

//if(longitude){
     myQuery.equalTo('longitude',-82.3641667);
//}

Does this make ANY sense? What I am trying to say is that as soon as I use an if statement, everything breaks

@ghost
Copy link

ghost commented Jul 27, 2016

I'm also facing same issue my cloud code not working after migrating to AWS.

@hramos
Copy link
Contributor

hramos commented Jul 27, 2016

@manikantasiripella you'll probably want to open a new issue with more details about your specific problem.

@hramos
Copy link
Contributor

hramos commented Jul 27, 2016

@ArchonLight the params should be passed in as numbers if you're calling the function that way. Which specific Parse iOS SDK are you using?

I'm afraid that at this point we don't have sufficient information to pin-point this as a Parse Server issue. I know you've tried many different things, but what would help is a small, reproducible set of steps that displays the actual issue with Parse Server. If it turns out to be in one of the SDKs, then open an issue against the SDK's repository.

@hramos hramos closed this as completed Jul 27, 2016
@TheMikeCannell
Copy link
Author

TheMikeCannell commented Jul 27, 2016

version 1.12.0
I don't know that is is a Parse Server problem. What I do know is that I didn't have this problem on parse.com and it has been working for many months when this cloud code was written.

What has changed during the migration process is an update to 1.12.0 to work with Parse Server, mLab, open-source Parse Server, AWS SDK via PODS, and AWS (probably different versions of Node, etc...). The code in Xcode hasn't changed.

@hramos I'd be happy to screen share and you can look through all the code.

@hramos
Copy link
Contributor

hramos commented Jul 27, 2016

Parse.com and Parse Server are completely different environments. Migrating to Parse Server does require some Cloud Code updates in some cases to account for this.

@TheMikeCannell
Copy link
Author

TheMikeCannell commented Jul 27, 2016

I completely understand and have made many CC updates, however, this one is very odd and I am not sure how I can proceed. What can I do to help you help me? Whether I use the app to send the params or I use CURL, the result is the same. I've sent as a Number and I've sent as a String. The results are the same.

@hramos
Copy link
Contributor

hramos commented Jul 27, 2016

A Cloud Code function not working in the same manner as Parse.com is too broad of an issue, so we'd need something more specific. We've discussed several things in this thread, so the question is what is actually blocking you from proceeding here.

If the issue is that Parse Server, when given a floating point number parameter, it passes in a String instead, then that's something we can look at here. We'd need a specific CURL request that demonstrates the issue in a specific Parse Server version. Don't use the Parse iOS SDK to make the request as we would need to isolate the issue to Parse Server.

If the issue is that the Parse iOS SDK converts a NSNumber parameter to a string when making a Cloud Code function call, then open an issue against the Parse iOS SDK repository on GitHub.

@TheMikeCannell
Copy link
Author

TheMikeCannell commented Jul 27, 2016

I have done the following in CURL and Xcode with the exact same results:

  1. send a String to the CC method and used equalTo on a column of Strings
  2. send a Number to the CC method and used equalTo on a column of Numbers

Both ways return the exact same results: my response contains objects that don't match the equalTo. Doesn't this rule out the SDK as the problem?

Now, if I hardcode the equalTo in Cloud Code using Number equalTo Number or using String equalTo String, my response has exactly the objects I want: objects limited to the objects that match the query. At no time am I comparing a string to a float or vice versa. Doesn't this rule out the Float comparison failure speculation?

Is it possible/probable that Parse Server's equalTo is comparing two objects rather than the values of two objects? Whereas parse.com was comparing the values of the objects. For instance, when you want to compare two objectIds you have to compare "object.objectIds" and not just "object".

Is something somehow wrapped?

@hramos
Copy link
Contributor

hramos commented Jul 27, 2016

What you're describing requires three separate components: the client making the call (curl, or iOS SDK), the server handling the call (parse.com Cloud Code, or Parse Server Cloud Code), and the SDK making the queries against Parse in your Cloud Code (a specific version of the Parse JavaScript SDK running within Cloud Code).

What I'm trying to get that is that, in order to re-open this issue, we'd need a clear description of an issue attributable to Parse Server. If you're only interested in debugging your Cloud function, then Stack Overflow is a better place to have that sort of discussion.

@steven-supersolid
Copy link
Contributor

@ArchonLight the best thing to do to help track down this issue is to post your latest curl statement, verbose server log (including the request to cloud code, the REST request that is then made, and the response), and source code for the simplest cloud code function that reproduces the bug. This is because there is already a lot of info and changes in this ticket so want to focus on a single issue.

You can also open a PR with a unit test that reproduces the bug.

I strongly recommend you use a fixed version of parse-server and not the version "latest" because you may get changes you don't expect. Also, a specific version is required to debug any issue here. Suggest going with 2.2.17 or whatever previous version works well for you.

The if statement stuff looks like a separate JavaScript code issue due to falsey values. If the values are falsey on request.params when they shouldn't be, then that could be a parse-server issue and it can be addressed here.

@mtrezza mtrezza added type:question Support or code-level question and removed 🔧 troubleshooting labels Jul 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:question Support or code-level question
Projects
None yet
Development

No branches or pull requests

5 participants