Parse-sdk-js: Convert Parse.Object to Json and save back to server doesn't work (with pointers)

Created on 23 Oct 2016  Â·  7Comments  Â·  Source: parse-community/Parse-SDK-JS

I tried to convert Parse.Object in json and save back to the server but seems to not work.

 //Get the object from the server
 var Home = Parse.Object.extend("Home");
 var query = new Parse.Query(Home);
 query.get("qaTGFbSkTi").then(function(home){
      var json = home.toJSON();
      json.area=234; // modify the json
      console.log(json); // Json correctly modified
      //home.set(json); // same if I use set() or save()
      home.save(json).then(function(res){ // save the modifications
          console.log(res);
       },function(err){
        console.log(err); //{code: 111, message: "This is not a valid Object"}
      });
      var object = Parse.Object.fromJSON(json);//Error: Cannot create an object without a className
      object.save().then(function(g){ 
        console.log(g); 
      },function(err){
        console.log(err);
      })
});

The converted Json object is in the following format(this the results of JSON.stringify(json)):

{
    "updatedAt": "2016-10-23T16:01:27.875Z",
    "createdAt": "2016-10-22T16:08:16.772Z",
    "volume": 180,
    "year": 1980,
    "area": 234,
    "windows": 7,
    "people": 1,
    "city": "Bern",
    "Owner": {
        "username": "test",
        "ACL": {
            "*": {
                "read": true
            },
            "OAhrAzI7HV": {
                "read": true,
                "write": true
            }
        },
        "updatedAt": "2016-10-01T14:46:16.438Z",
        "createdAt": "2016-08-08T18:39:38.834Z",
        "mqttPassword": "1231231",
        "mqttUsername": "FGTCG",
        "mqttServer": "xx",
        "name": "xx",
        "lastName": "xx",
        "location": "xx",
        "city": "xx",
        "email": "[email protected]",
        "isCoupled": false,
        "sessionToken": "r:d2f6a362d9fa1c97bc071299f1f420cc",
        "objectId": "OAhrAzI7HV",
        "__type": "Object",
        "className": "_User"
    },
    "objectId": "qaTGFbSkTi"
}

I also tried by converting the object with _.toFullJSON() and in this case it doesn't show an error but the object is not saved on the database.

What I'm doing wrong?

stale

Most helpful comment

The method you're attempting works for trivial cases, so I don't doubt that you found it working before, but it should not be expected to work for more complex cases such as pointers. The code above is also unsafe from a data consistency perspective.

Here's what your code is doing:
1) convert the object to a full JSON format
2) modify a single field
3) (here's the biggest issue) calling save(json) replaces every key in the JSON object with the potentially-unencoded value.

The first problem here is that you're potentially blowing away any changes from another client. Consider the following scenario:
Client A and Client B both fetch the same object
Client A sets year to 1981 and tries to save
Client B sets people to 2 and tries to save
Whichever client saves _last_ will blow away all the changes of the other clients that occurred between fetching the object and saving it again.

The second problem is that Parse Objects are designed to be used as a higher-level abstraction. They represent ugly wire formats like {__type: 'GeoPoint', latitude: ..., longitude: ...} in a way that is easy to deal with. This goes for files, dates, pointers... you get the picture. Calling set() or save() with nested fields containing encoded data is not designed to be supported. It will work in some scenarios, but it's not designed to work in all.

If you really want to be interfacing at a JSON level, you should not be using Parse.Object at all. You should use the underlying RESTController to make calls directly to the API. I'm sorry I can't be of much more help here, but when the SDK is used in ways it's not intended to be used, there's not much I can do.

All 7 comments

Can I ask why you're trying to modify the object in its JSON form? What you're doing really isn't intended behavior, and shouldn't be expected to be supported.

Why not just:

// ...
query.get("qaTGFbSkTi").then(function(home){
      home.set('area', 234);
      home.save().then(function(res) {
// ...

I need it for exemple when I'm working with AngularJS.
I need a JSON the make the binding work so that I can just pass the homeJson object to the view like:

//On angular
query.get("qaTGFbSkTi").then(function(home){
      $scope.homeJson = home.toJSON();
});

//On the view
<input type="text" ng-model="homeJson.city">
<input type="number" ng-model="homeJson.area">

In this way the Json change accordigly to the input fields automatically.
Then I can save the homeJson object back to Parse and I just need set it to the parse object.

home.save($scope.homeJson).then(function(res){ // save the modifications
    console.log(res);
},function(err){
   console.log(err);
});

If I use a Parse.Object in the Angular model it doesn't work and I have to call the get() function for every field and the a set() for each one when saving back to Parse and this is what the binding is supposed to avoid.

As far as I remember I have already used this method and it was working but I don't remember on what release it was.

I'm open to know if there is a simpler solution that support the binding with Angular of course.

I also tried to use the Parse.Object.fromJSON(json) as explained in my previous message and it does not throw an error but the object is not saved into the database. This at least it is supposed to work right?

Tried Migrating from 1.4 SDK to 1.9 SDK.
Facing Same Issue in Angular!

@Simone-cogno have you found any solutions?

I didn't found a solution for the JSON conversion. But for the binding with with Angular I will probably use something similar to https://github.com/rafbgarcia/angular-parse-wrapper that use the same conect explained here http://slidebean.com/blog/parse-angularjs. Seems a more clean solution.

The method you're attempting works for trivial cases, so I don't doubt that you found it working before, but it should not be expected to work for more complex cases such as pointers. The code above is also unsafe from a data consistency perspective.

Here's what your code is doing:
1) convert the object to a full JSON format
2) modify a single field
3) (here's the biggest issue) calling save(json) replaces every key in the JSON object with the potentially-unencoded value.

The first problem here is that you're potentially blowing away any changes from another client. Consider the following scenario:
Client A and Client B both fetch the same object
Client A sets year to 1981 and tries to save
Client B sets people to 2 and tries to save
Whichever client saves _last_ will blow away all the changes of the other clients that occurred between fetching the object and saving it again.

The second problem is that Parse Objects are designed to be used as a higher-level abstraction. They represent ugly wire formats like {__type: 'GeoPoint', latitude: ..., longitude: ...} in a way that is easy to deal with. This goes for files, dates, pointers... you get the picture. Calling set() or save() with nested fields containing encoded data is not designed to be supported. It will work in some scenarios, but it's not designed to work in all.

If you really want to be interfacing at a JSON level, you should not be using Parse.Object at all. You should use the underlying RESTController to make calls directly to the API. I'm sorry I can't be of much more help here, but when the SDK is used in ways it's not intended to be used, there's not much I can do.

It's also possible to use the set(json) function. As the documentation says:

Parse automatically figures out which data has changed so only “dirty” fields will be sent to the Parse Cloud. You don’t need to worry about squashing data that you didn’t intend to update.

For the second point you mentioned I'm asking myself why to provide a method fromJson() if you cannot create new Parse.Object with a pointer. Would be quite limited and I'm not sure it's really like this, because I read several articles that used it with pointers, even if using with some ungly json formats.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bezi picture bezi  Â·  4Comments

anhhtz picture anhhtz  Â·  3Comments

Jonarod picture Jonarod  Â·  6Comments

oallouch picture oallouch  Â·  4Comments

guilhermevini picture guilhermevini  Â·  6Comments