Skip to content
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

Cloud Code object.save() results in 'object not found' with very strange PUT command #2098

Closed
MobileVet opened this issue Jun 19, 2016 · 11 comments

Comments

@MobileVet
Copy link

Issue Description

I have a simple Cloud Code command to create or update an object. If there is NO objectId passed in, the routine creates a new object and returns the objectId. If the objectId exists in the parameter list, it fetches the object and updates the parameters accordingly.

The routine works for new objects fine.

The object.save() is failing when I try to update an object, despite the object.fetch() sub-routine working.
error: code=101, message=Object not found.

Verbose server logs indicate a very strange PUT command...
verbose: PUT /parse/classes/Receipt/[object%20Object]**

Object ACL is public r+w

Cloud Code

Parse.Cloud.define("uploadReceipt", function(request,response) {
    var Receipt = Parse.Object.extend("Receipt");
    var receipt = new Receipt();

    // passed in parameters are ['property' : ['type' : t, 'value' : v]]
    var dict = request.params;
    var objectIdDict = dict["objectId"];
    Parse.Promise.as().then(function() {
        // if we already have an objectId we are UPDATING
        // Need to FETCH first
        if (objectIdDict != undefined) {
            receipt.set("objectId",objectIdDict["value"]);
            return receipt.fetch();
        }
        else {
            return Parse.Promise.as(receipt);
        }

    }).then(function(receipt) {
        // copy over the keys from our passed in parameters to the object
        for (var key in dict) {
            //console.log("Key: " + key + "   Value: " + dict[key]["value"]);
            if (dict[key]["type"] == "Raw") {
                receipt.set(key,dict[key]["value"]);
            }
            else if (dict[key]["type"] == "Date" && key != "updatedAt") {
                var time = dict[key]["value"] * 1000;   // milliseconds
                receipt.set(key,new Date(time));
            }
            else {
                // object type
                var Obj = Parse.Object.extend(dict[key]["type"]);
                var newObj = new Obj();
                newObj.id = dict[key]["value"];
                receipt.set(key,newObj);
            }
        }

        // make sure our user is set
        receipt.set("user",request.user);

        // adjust the status because it has now been uploaded
        receipt.set("status",RECEIPT_SUBMITTED);
        return receipt.save();

    }).then(function(receipt) {
        response.success({"status":receipt.get("status"),"objectId":receipt.id});

    },function (error) {
        response.error(error);
    });
});

Steps to reproduce

  1. Call the cloud code from iOS SDK with data for a new object
  2. Notice that the command works and a new object is added to the database
  3. Call the command again with updated information
  4. Notice that the command fails with object not found

Expected Results

Object should be updated accordingly

Actual Outcome

error: code=101, message=Object not found.

Environment Setup

  • Server
    • parse-server version: 2.2.12
    • Operating System: Mac OS X 10.11.5
    • Hardware: MacBook Pro 2010
    • Localhost or remote server? Localhost
    • Javascript: Parse/js1.8.5
    • NodeJS 5.10.1
  • Database
    • MongoDB version: 3.2.4
    • Hardware: MacBook Pro 2010
    • Localhost or remote server? Localhost

Logs/Trace

** Storing NEW object returns **

verbose: POST /parse/classes/Receipt { 'user-agent': 'node-XMLHttpRequest, Parse/js1.8.5 (NodeJS 5.10.1)',
accept: '/',
'content-type': 'text/plain',
host: 'localhost:1337',
'content-length': '471',
connection: 'close' } {
"date": {
"__type": "Date",
"iso": "2016-06-19T00:30:37.492Z"
},
"category": {
"__type": "Pointer",
"className": "Category",
"objectId": "XZ1bSHtZBY"
},
"status": 0,
"amount": 61.45,
"notes": "Hopefully this works well",
"gui_status": -1,
"currency": "USD",
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "vL4ih9BAX8"
}
}
verbose: {
"status": 201,
"response": {
"objectId": "GJaXcf7fLD",
"createdAt": "2016-06-19T00:30:57.092Z"
},
"location": "http://localhost:1337/parse/classes/Receipt/GJaXcf7fLD"
}
Finished
verbose: {
"response": {
"result": {
"status": 0,
"objectId": "GJaXcf7fLD"
}
}
}

** Attempt to Update object returns **

verbose: PUT /parse/classes/Receipt/[object%20Object] { 'user-agent': 'node-XMLHttpRequest, Parse/js1.8.5 (NodeJS 5.10.1)',
accept: '/',
'content-type': 'text/plain',
host: 'localhost:1337',
'content-length': '473',
connection: 'close' } {
"category": {
"__type": "Pointer",
"className": "Category",
"objectId": "XZ1bSHtZBY"
},
"status": 0,
"amount": 5.47,
"notes": "How about now",
"gui_status": 0,
"date": {
"__type": "Date",
"iso": "2016-06-19T00:12:25.788Z"
},
"currency": "USD",
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "vL4ih9BAX8"
}
}
verbose: error: code=101, message=Object not found.
ParseError { code: 101, message: 'Object not found.' }
verbose: error: code=141, code=101, message=Object not found.

@araskin
Copy link

araskin commented Jun 19, 2016

Can I ask you to try something?

Can you replace the following code

            receipt.set("objectId",objectIdDict["value"]);
            return receipt.fetch();

with

return receipt.get(objectIdDict["value"])

Does that work?

@MobileVet
Copy link
Author

MobileVet commented Jun 20, 2016

@araskin Thanks for the suggestion.

I tried it, but it does not work as the object is not actually fetched. As far as I know, 'get' on Parse objects is for retrieving properties... not getting the actual object.

Interestingly, the final receipt.save() still produces the same resulting REST call
verbose: PUT /parse/classes/Receipt/[object%20Object]

@araskin
Copy link

araskin commented Jun 20, 2016

@MobileVet I appoglize Rob. You are right 'get' is for getting property so what I should have said was this:

                var query = new Parse.Query("Receipt");
                return query.get(objectIdDict["value"]);

@MobileVet
Copy link
Author

@araskin The query works... but still get the same error when I attempt to save it after changing some values. Pretty sure the fetch() works as well.

Did some 'take it out, put each line back in one by one' debugging and narrowed it down to the else clause that adds other object types to the receipt:

        else {
            // object type
            var Obj = Parse.Object.extend(dict[key]["type"]);
            var newObj = new Obj();
            newObj.id = dict[key]["value"];
            receipt.set(key,newObj);
        }

I don't understand why this works fine on NEW objects, but somehow changes the PUT call when done on an object that exists.

@araskin
Copy link

araskin commented Jun 20, 2016

Can you debug it? Make sure the value you are setting is what you are expecting it to be? Sent from my BlackBerry - the most secure mobile device From:[email protected]:June 19, 2016 8:21 PMTo:[email protected]:[email protected]:[email protected]; [email protected]:Re: [ParsePlatform/parse-server] Cloud Code object.save() results in 'object not found' with very strange PUT command (#2098) @araskin The query works... but still get the same error when I attempt to save it after changing some values. Pretty sure the fetch() works as well.

Did some 'take it out, put each line back in one by one' debugging and narrowed it down to the else clause that adds other object types to the receipt:

    else {
        // object type
        var Obj = Parse.Object.extend(dict[key]["type"]);
        var newObj = new Obj();
        newObj.id = dict[key]["value"];
        receipt.set(key,newObj);
    }

I don't understand why this works fine on NEW objects, but somehow changes the PUT call when done on an object that exists.

—You are receiving this because you were mentioned.Reply to this email directly, view it on GitHub, or mute the thread.

@MobileVet
Copy link
Author

@araskin Yep... console log shows it is valid... and it works on new receipts. Verbose log shows the valid object (I think, maybe I am missing something). See the REST JSON below.

verbose: PUT /parse/classes/Receipt/[object%20Object] { 'user-agent': 'node-XMLHttpRequest, Parse/js1.8.5 (NodeJS 5.10.1)',
accept: '/',
'content-type': 'text/plain',
host: 'localhost:1337',
'content-length': '485',
connection: 'close' } {
"category": {
"__type": "Pointer",
"className": "Category",
"objectId": "XZ1bSHtZBY"
},
"status": 0,
"amount": 0.61,
"notes": "Hopefully this works well",
"gui_status": 0,
"date": {
"__type": "Date",
"iso": "2016-06-19T00:30:37.492Z"
},
"currency": "USD",
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "vL4ih9BAX8"
}
}
verbose: error: code=101, message=Object not found.
ParseError { code: 101, message: 'Object not found.' }
verbose: error: code=141, code=101, message=Object not found.

@araskin
Copy link

araskin commented Jun 20, 2016

Obviously the issue is in the PUT URL but you all ready know that.  The object not found error is because the objectId  that it is expecting is invalid. So I guess it has something to do with the way you are instantiating the object. I would start by implementing https://github.com/node-inspector/node-inspector and then debugging the cloud function.  Sent from my BlackBerry - the most secure mobile device From:[email protected]:June 19, 2016 8:37 PMTo:[email protected]:[email protected]:[email protected]; [email protected]:Re: [ParsePlatform/parse-server] Cloud Code object.save() results in 'object not found' with very strange PUT command (#2098) @araskin Yep... console log shows it is valid... and it works on new receipts. Verbose log shows the valid object (I think, maybe I am missing something). See the REST JSON below.

verbose: PUT /parse/classes/Receipt/[object%20Object] { 'user-agent': 'node-XMLHttpRequest, Parse/js1.8.5 (NodeJS 5.10.1)',
accept: '/',
'content-type': 'text/plain',
host: 'localhost:1337',
'content-length': '485',
connection: 'close' } {
"category": {
"__type": "Pointer",
"className": "Category",
"objectId": "XZ1bSHtZBY"
},
"status": 0,
"amount": 0.61,
"notes": "Hopefully this works well",
"gui_status": 0,
"date": {
"__type": "Date",
"iso": "2016-06-19T00:30:37.492Z"
},
"currency": "USD",
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "vL4ih9BAX8"
}
}
verbose: error: code=101, message=Object not found.
ParseError { code: 101, message: 'Object not found.' }
verbose: error: code=141, code=101, message=Object not found.

—You are receiving this because you were mentioned.Reply to this email directly, view it on GitHub, or mute the thread.

@flovilmart
Copy link
Contributor

flovilmart commented Jun 27, 2016

It seems that something is wrong with your logic in that code, and that may be better suited for stack overflow.

Make sure all the calls setting objectId on an object are done with a proper string.

As for the solution,

because you don't delete the objectId key from the params, this falls into the else, creating a new object.
This doesn't happen when creating a new object, because the objectId key is not set when calling the cloud function.

you else should be

} else if (key != "objectId") {
// load the objects
} else  {
console.log(`ignore ${key}`);
}

@MobileVet
Copy link
Author

@flovilmart Thanks for looking at this. I have submitted it to SO and just added a bounty.

I don't think this is a code logic issue... the object is appropriately fetched and the values included in the PUT look correct, except for the call itself.

I would expect to see
PUT /parse/classes/Receipt/objectId

Instead I see
PUT /parse/classes/Receipt/[object%20Object]

Additionally, this only happens if I include the section for adding in object pointers. If I only include raw values (string, num) everything works fine.

@flovilmart
Copy link
Contributor

flovilmart commented Jul 7, 2016

Did you try doing

var objectIdDict = dict["objectId"];
delete dict['objectId']

I'm 100% confident that at one point, you're setting an objectId on an object, and that objectId is not a string...

/* with 

dict  = {
   objectId: {
      value: "ObjectId"
   }
}
*/
var Obj = Parse.Object.extend(dict[key]["type"]);
// <=> var Obj = Parse.Object.extend(undefined)
var newObj = new Obj();
newObj.id = dict[key]["value"];
// <=> newObj.id == "ObjectId"
receipt.set(key,newObj);
// <=> receipt.set("objectId",newObj); 
// and newObj is an object

@MobileVet
Copy link
Author

MobileVet commented Jul 8, 2016

Figured it out. @flovilmart, You were on the right track... thank you for your suggestions.

In the case of 'updating' an object, I was including a dictionary entry for the Receipt. This was successfully retrieving the Receipt that I wanted to update.

However, the issue was that once I pulled in the receipt object and was iterating through my dictionary of properties... I ran into the Receipt object information again. Thus I was trying to add a property of Receipt pointer to my Receipt with the pointer being itself! Ugh.

The very last else clause needed a condition on it to NOT include the pointer to Receipt (itself)

      else if (dict[key]["type"] != "Receipt"){
        // object type, but don't include ourself!  (the Receipt)
        var Obj = Parse.Object.extend(dict[key]["type"]);
        var newObj = new Obj();
        newObj.set("objectId",dict[key]["value"]);
        receipt.set(key,newObj);
        //console.log(dict[key]["type"] + ": " + newObj.id);
      }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants