Closed ibrennan closed 8 years ago
Just to further compound the potential bug, on the Cloud Code if we do:
response.success(JSON.stringify(comments));
This will mean the response is sent as a String representation of the JSON. On the frontend we then parse the String and turn it back into JSON:
comments = JSON.parse(comments);
This results in the correctly formatted JSON representation of the data
Every response coming from the server is decoded to re-inflate special types that don't have a native JSON representation: Date
, Parse.File
, Parse.GeoPoint
, etc. This also happens for Parse.Object
. Any time an object comes back with a __type
field, the SDK interprets it as an object that needs to be inflated. This is exactly the intended behavior, and the only way the SDK can work in the first place.
To pass back objects that you don't want to be inflated, you'd want to avoid passing the __type
field back. Here's the confusing part... the brief view of output you include above shows the __type
fields, but calling toJSON()
in your code as described would not include that field, nor the className
field. Here's the relevant code:
https://github.com/ParsePlatform/Parse-SDK-JS/blob/master/src/ParseObject.js#L410
I'm going to need some more information, because the code you wrote shouldn't be outputting the output you provided, and the output you provided would be expected by design to produce the client counterparts you're seeing.
Thanks for the speedy reply @andrewimm, makes sense about what you're saying regarding the re-inflating of types.
I can't see the in the code you linked to where __type and className get stripped out though? I followed it back to the encode.js and couldn't see reference to it there.
Would you like anything more from me, it seems like we should be able to reproduce the __type and className field removal issue in a simple script
Sorry, I was trying to point out that the two fields aren't added in the first place, not that they're stripped out. When actual Parse Objects are passed back to the client from cloud code, the middleware calls a private method called _toFullJSON()
to add those missing fields.
For now, could I just get the full console output of the cloud code you've included above? If necessary, I'll ask you for a repro case later.
Here's the output of comments
, which is the array result of the .find():
[ ParseObjectSubclass { className: 'Comment', _objCount: 0, id: 'Ems4SSqa6w' },
ParseObjectSubclass { className: 'Comment', _objCount: 2, id: 'glwheqifgI' },
ParseObjectSubclass { className: 'Comment', _objCount: 4, id: 'xv3pofphRb' },
ParseObjectSubclass { className: 'Comment', _objCount: 6, id: 'BViHmBCEhX' },
ParseObjectSubclass { className: 'Comment', _objCount: 8, id: '6mOLGIC7OY' },
ParseObjectSubclass { className: 'Comment', _objCount: 10, id: 'bONunA0osL' },
ParseObjectSubclass { className: 'Comment', _objCount: 12, id: 'w7smqUS8T5' },
ParseObjectSubclass { className: 'Comment', _objCount: 14, id: 'ZRrz4KRW8M' },
ParseObjectSubclass { className: 'Comment', _objCount: 16, id: 'CZYFaopk3F' },
ParseObjectSubclass { className: 'Comment', _objCount: 18, id: 'KAFQODiZ6H' } ]
Here's the output from the Object at index 0 in that array after calling .toJSON() on it:
{ content: 'Let\'s do Sushirrito.',
parent:
{ title: 'I\'m Hungry',
updatedAt: '2016-04-14T14:25:20.847Z',
createdAt: '2016-04-14T14:25:20.847Z',
objectId: 'te85roF7fv',
__type: 'Object',
className: 'Post' },
updatedAt: '2016-04-14T14:25:20.919Z',
createdAt: '2016-04-14T14:25:20.919Z',
objectId: 'Ems4SSqa6w' }
The __type and className are only being exposed on the 'parent' key, which is a Pointer to another Class object.
Okay. I'd actually classify all of this to be expected behavior. When encoding an object to JSON, we still expect that nested fields will contain the appropriate __type
fields, since it's impossible to add these after the fact if they're desired. And since the __type
fields are being passed, I'd expect the client the inflate these into Parse.Objects.
I'd recommend that you simply rewrite your delivery code to ensure the nested fields are also coming back in your expected format. Either something like:
comments.map(function(comment) {
var json = comment.toJSON();
if (json.parent) {
delete json.parent.__type;
}
});
or write your own encoding function that only passes back the fields you need on the client, whitelist style.
Closing this as behaving as intended.
How am I supposed to call .toJSON on the root level object and the loop through it and call .toJSON on all of it's properties as well? For instance what if I have a Date, Parse.File and Parse.GeoPoint all associated to this one object? Maybe I'm missing something, but this seems really awkward to me.
@parkej60 toJSON
recursively calls toJSON
on all its nested children as well. The reason this whole thing seems awkward is because it is not the way you are supposed to return a Parse Object from Cloud Code. If you call response.success()
with your result, the encoding is properly done for you.
@andrewimm I am using response.success, but not directly return parse objects from Cloud Code. I'm sending something like this response.success({"queryIdentifier":0,"results":restaurantArray}); restaurantArray is an array of Parse Objects.
@parkej60 you should be able to call exactly that, and it should work. If restaurantArray
is an array of viable Parse Objects, it should encode properly.
Well, I'll keep digging into it then I guess.
@andrewimm Ok So here's an interesting example.
var Restaurant = Parse.Object.extend("Restaurant");
var query = new Parse.Query(Restaurant);
query.limit(20);
query.descending('rating');
query.find().then(function(restaurants){
view.$el.html(view.template({restaurants:restaurants}));
},function(error){
console.error("Error: " + error.code + " " + error.message);
});
This also returns the objects in the format and it's a direct server query.
{
_objCount: 0
className: "Restaurant"
id: "NtfeOn3dFH"
}
Here's an example of the database structure for this object.
{
"_id": "NtfeOn3dFH",
"_created_at": {
"$date": "2014-05-20T04:50:22.292Z"
},
"_p_createdBy": "_User$3eVAVkR4Rk",
"_updated_at": {
"$date": "2014-06-04T22:01:04.324Z"
},
"address1": "615 W. Randolph",
"address2": "",
"approved": true,
"beenThereCount": 6,
"body": "a wine bar and restaurant with a menu of rustic food, including handcrafted charcuterie, inspired by the wine-growing regions of Southern France, Italy, Portugal and the coast of Spain. In addition to cuisine that reflects the aromas, flavors and colors of the Mediterranean, the wine bar features a moderately priced wine list that focuses on boutique vineyards throughout southwestern Europe.",
"city": "Chicago",
"country": "US",
"dress_code": "",
"facebook_handle": "http://www.facebook.com/home.php#!/pages/avec/55233720395",
"favoriteCount": 48,
"godfatherRecommended": true,
"hashtags": [],
"head_chef": "",
"inTop100": true,
"location": [
-87.6433717,
41.884343
],
"lowerCaseCity": "chicago",
"lowerCaseNeighborhood": "near west side",
"lowerCaseTerms": [],
"lowerCaseTitle": "avec",
"menu_url": "http://avecrestaurant.com/menus/3-dinner-menu#",
"neighborhood": "Near West Side",
"nid": "129",
"on_opentable": "0",
"only_local": "1",
"phone": "312-377-2002",
"picture": "14014353-b5f6-4679-9c7b-9c38278f6f9f-129-129.jpg",
"pictureThumbnail": "a166b80a-0332-4861-89fb-4123069a46f3-thumbnail.jpg",
"pinterest": "",
"price_level_id": 3,
"rating": 3606,
"recommendCount": 13,
"reservation_url": "",
"state": "IL",
"terms": [
"Fusion / Eclectic"
],
"title": "Avec",
"twitter_handle": "",
"vaultedCount": 11,
"website": "http://www.avecrestaurant.com/",
"words": [
"a",
"wine",
"bar",
"restaurant",
"with",
"a",
"menu",
"of",
"rustic",
"food",
"including",
"handcrafted",
"charcuterie",
"inspired",
"by",
"wine",
"growing",
"regions",
"of",
"southern",
"france",
"italy",
"portugal",
"coast",
"of",
"spain",
"addition",
"to",
"cuisine",
"that",
"reflects",
"aromas",
"flavors",
"colors",
"of",
"mediterranean",
"wine",
"bar",
"features",
"a",
"moderately",
"priced",
"wine",
"list",
"that",
"focuses",
"on",
"boutique",
"vineyards",
"throughout",
"southwestern",
"europe"
],
"zipCode": "60661"
}
Hi @parkej60 , were you able to work out a solution for this? As this still seems to be an issue, at least in my case.
Hi! so finally is there any solutions for this issue?
Version affected: _1.8.2 (and previous) _Enviroments: Node.JS v4.4.3, OSX El Capitan Chrome 49.0.2623.110 Steps to reproduce:
Summary Something appears to happen to the Object between the response.success() and the resolved data from Parse.Cloud.run()
Server side console.log result:
Frontend result: