question

xrosstales avatar image
xrosstales asked

CloudScript JSON.parse from "server.GetUserReadOnlyData"

I got a problem with JSON.parse the object the return from function server.GetUserReadOnlyData.

It seem like I can't access any property or field inside an object that parse from function GetUserReadOnlyData.

Assume that I have Player Data(Title) like this

Here the code that I reproduce.

handlers.CheckIn = function(args) {

	var result = {};

	var GetUserReadOnlyDataRequest = {
		"PlayFabId": currentPlayerId,
		"Keys": ["CheckInTracker"]
	};
	var GetUserReadOnlyDataResponse = server.GetUserReadOnlyData(GetUserReadOnlyDataRequest);

	var tracker = {};
	if (GetUserReadOnlyDataResponse.Data.hasOwnProperty("CheckInTracker")) {

		tracker = JSON.parse(GetUserReadOnlyDataResponse.Data["CheckInTracker"].Value);

		log.info("tracker");
		log.info(tracker);

		log.info("get field by .");
		log.info(tracker.LoginStreak);
		log.info(tracker.NextEligibleGrant);

		log.info("get field by []");
		log.info(tracker["LoginStreak"]);
		log.info(tracker["NextEligibleGrant"]);

		log.info("end tracker");
	}

	return result;
}
// The log in this case would be
// tracker
// {"LoginStreak":1,"NextEligibleGrant":1490090129539}
// get field by .
// null
// null
// get field by []
// null
// null
// end tracker

And when i test it like this.

handlers.TestJsObject = function(args) {

	var result = {};
	var tracker = JSON.parse("{\"LoginStreak\":1,\"NextEligibleGrant\":1490090129539}");

	log.info("tracker");
	log.info(tracker);

	log.info("get field by .");
	log.info(tracker.LoginStreak);
	log.info(tracker.NextEligibleGrant);

	log.info("get field by []");
	log.info(tracker["LoginStreak"]);
	log.info(tracker["NextEligibleGrant"]);

	log.info("end tracker");

	return result;
}
// The log in this case would be
// tracker
// {"LoginStreak":1,"NextEligibleGrant":1490090129539}
// get field by .
// 1
// 1490090129539
// get field by []
// 1
// 1490090129539
// end tracker

I have no idea what going on with the object that receive from PlayFab database. Please help.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Joshua Strunk avatar image
Joshua Strunk answered

I suspect the problem is that your value stored in UserReadOnlyData is actually a double serialized JSON encoded string, not a JSON encoded string. This is why in your test pulling from PlayFab your log prints out the what appears to be a the same value as in your hard coded example for tracker. This is also why you can see quotes around your value "{}" and all the inner quotes are visibily escaped \"

A quick way to test this would be to actually JSON.parse the value twice.

tracker = JSON.parse(JSON.parse(GetUserReadOnlyDataResponse.Data["CheckInTracker"].Value));
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

Can you give us the Title ID in question, and the PlayFab ID of a player account you're using for this test?

1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

xrosstales avatar image xrosstales commented ·

Thank for the quick response.

Here the TitleID : CA6B

PlayFabID : 54F1B39DAC1BF13E

0 Likes 0 ·
paulcmoi51 avatar image
paulcmoi51 answered

I had the same issue,

The data you receive from "GetUserReadOnlyDataResponse.Data["CheckInTracker"].Value" seems not to be a valid string but something like an "object".

The way i resolved it is to call JSON.Stringify to cast your json in a valid string. Then you can parse it again with JSON.Parse.

Try to modify your line 14 : tracker = JSON.parse(JSON.stringify(GetUserReadOnlyDataResponse.Data["CheckInTracker"].Value));

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

xrosstales avatar image
xrosstales answered

I finally found the problem thank to @paulcmoi51 who hint me about "string" part.

Here a little more of debugging and it say every thing.

		var dataValue = GetUserReadOnlyDataResponse.Data["CheckInTracker"].Value;

		log.info("dataValue");
		log.info(dataValue);

		log.info("JSON.parse dataValue");
		tracker = JSON.parse(dataValue, (_key, _val) => {
			log.info("[] " + _key + " | " + _val + " ]");
			return _val;
		});

		log.info("tracker");
		log.info(tracker);
//The log would be
// dataValue
// "{\"LoginStreak\":1,\"NextEligibleGrant\":1490183204031}" // clearly a string
// JSON.parse dataValue
// [  | {"LoginStreak":1,"NextEligibleGrant":1490183204031} ] // the key is empty with this object as value.
// tracker
// {"LoginStreak":1,"NextEligibleGrant":1490183204031} // look normal but can't access via tracker variable.	

So the root of all problem was my JSON in Player Data(Title) should not be like this.

"{\"LoginStreak\":1,\"NextEligibleGrant\":1490183204031}"

But Like this instead.

{"LoginStreak":1,"NextEligibleGrant":1490183204031}

So I Change the code where I save my data like this

function UpdateTrackerData(data) {
	var UpdateUserReadOnlyDataRequest = {
		"PlayFabId": currentPlayerId,
		"Data": {}
	};
	//FROM
	UpdateUserReadOnlyDataRequest.Data[CHECK_IN_TRACKER] = JSON.stringify(data);
	//TO
	UpdateUserReadOnlyDataRequest.Data[CHECK_IN_TRACKER] = data;

	server.UpdateUserReadOnlyData(UpdateUserReadOnlyDataRequest);
}

The function "UpdateTrackerData" was a function I copy from PlayFab ProgressiveRewardsRecipe. Please fix it.

Ps. Apology for my bad grammar. English is not my native langauge.

1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image brendan commented ·

Essentially yes, though I would point out that your user data actually is

"{\"LoginStreak\":1,\"NextEligibleGrant\":1490183204031}"

The issue is that the user data key/value pairs are always string/string, so by entering it literally that way in the Game Manager, that results in the user data being stored as

"\"{\\\"LoginStreak\\\":1,\\\"NextEligibleGrant\\\":1490167755772}\""

Glad to hear you're not blocked on this - let us know if you run into any other issues.

0 Likes 0 ·
Afranio avatar image
Afranio answered

know this is an old topic but no answer here really fixes the problem in the recipe's CloudScript, the problem is that when you first enter the script leads you to the ResetTracker function which returns a stringified value from reset which is assigned to tracker, so when the tracker is sent to UpdateTrackerData(data) it is sent as a string instead of a JSON variable which is what the UpdateTrackerData function expects, so the result of using stringify on a string is the string having these '\' before the quotes which is sent to the CheckInTracker on Player data and when you JSON.parse it you still have a string so if you try using tracker[TRACKER_NEXT_GRANT] you will get a null value.

The solution is simple in the return statement from the ResetTracker function switch this

return JSON.stringify(reset);

with this

return JSON.parse(JSON.stringify(reset));

I hope I helped anyone still having this problem and hope the recipe's CloudScript gets fixed soon

1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image brendan commented ·

Thanks, I have a backlog item open for our tools team to do a pass on the samples to fix things like this, but if you've already fixed it in your copy, why not just do a pull request to our GitHub repo? The tools team could then just review the change and accept it, if it resolves the issue. That would be the fastest way to get this updated.

0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.