For inspiration, you may want to look into the way some of the json based api's (ex: json api, HAL) handle embedding.
One simple answer is to track your data in a key value store. For example
{ "/players/0" : {...}
, "/players/1" : {...}
, "/players/2" : {...}
, "/players/3" : {...}
, "/teams/0" : {...}
, "/teams/1" : {...}
}
And then you describe the players assigned to your team using local references
, "/teams/0" :
{ refs :
[ "/players/0"
, "/players/1"
]
}
As it happens, this scheme covers the case where you have identifiers too. Or where you only have some identifiers
, "/teams/0" :
{ refs :
[ "/players/0"
, "/players/2ad8cabe-2f93-11e6-ac61-9e71128cae77"
]
}
There are fancier versions of this idea (see the links).
That said, I've been down this road myself, and I really tied myself in knots until I concluded: if what you really have is a list of names, rather than a list of players, admit that to yourself, code it that way, and deal with it. It's the more honest way of representing what's going on in the domain at that point in time.
In which case, the payload of your message should look very close to:
{ "Team 1" :
[ "Player 1"
, "Player 2"
]
, "Team 2" :
[ "Player 3"
, "Player 4"
]
}
If that makes you twitchy, remember: this isn't a description of your domain objects; it's a message. The changes it makes to your domain are a side effect. Jim Webber covers this in the introduction to this talk.
Answer from VoiceOfUnreason on Stack ExchangeFor inspiration, you may want to look into the way some of the json based api's (ex: json api, HAL) handle embedding.
One simple answer is to track your data in a key value store. For example
{ "/players/0" : {...}
, "/players/1" : {...}
, "/players/2" : {...}
, "/players/3" : {...}
, "/teams/0" : {...}
, "/teams/1" : {...}
}
And then you describe the players assigned to your team using local references
, "/teams/0" :
{ refs :
[ "/players/0"
, "/players/1"
]
}
As it happens, this scheme covers the case where you have identifiers too. Or where you only have some identifiers
, "/teams/0" :
{ refs :
[ "/players/0"
, "/players/2ad8cabe-2f93-11e6-ac61-9e71128cae77"
]
}
There are fancier versions of this idea (see the links).
That said, I've been down this road myself, and I really tied myself in knots until I concluded: if what you really have is a list of names, rather than a list of players, admit that to yourself, code it that way, and deal with it. It's the more honest way of representing what's going on in the domain at that point in time.
In which case, the payload of your message should look very close to:
{ "Team 1" :
[ "Player 1"
, "Player 2"
]
, "Team 2" :
[ "Player 3"
, "Player 4"
]
}
If that makes you twitchy, remember: this isn't a description of your domain objects; it's a message. The changes it makes to your domain are a side effect. Jim Webber covers this in the introduction to this talk.
This is a really nice question.
The problem arises because you are modeling redundant information and try to avoid redundancy at the same time.
On the one hand, you have a collection of players
players = [{"id":"1"},{"id":"2"},{"id":"3"}]
On the other hand, you have a colletion of teams, which itself consist of subsets from players.
teams = [ {"id":"1", "players": [ players[0], players[1] ]} ]
This gives a composition:
players = [{id:1},{id:2},{id:3},{id:4}]
teams =[ {id:1, players:[players[0], players[1]]} ]
data = {players:players, teams:teams}
Look here for the Fiddle and watch the result.
As you see, the references cause redundant information in JSON.stringify, because you have redundant information in your data object.
The problem of avoiding redundancy arises when sending data to the server.
Take a step back.
What do you want to tell the server?
a) Here you have a list of teams, please persist it for me. I come back to you later. Oh, by the way, the teams contain the following players blablabla
b) Here you have a list of players. Keep 'em safe for me. I need them later to build `teams.
Your model shows, that you are not clear.
There are several usecases:
I) I want to create new players
IIa) I want to create new teams
IIb) I want to put players in teams
I) In a REST-context, you could issue a POST to /players.
IIa,b) You POST to /teams your collection of teams.
How to deal with the situation, that you want to save requests and do not issue a single POST for each creation of a new player (and an additional one for submitting the team)?
I would go for the following:
You have a collection of players: some of them have an id, indicating, that they were already persisted; some of them don't.
If you create teams, you issue only one POST request with the teams, containing the full player objects.
[{"name":"team1", "players":[{"id":"1", "name":"player1"}, "name":"player2"}]}, ... ] // you get the idea
The server isn't interested in knowing explicitely how many players there are: it is implicitely clear: it's the sum of all players (which might be the sum of all players in all teams).
The server has to figure out, how to persist the players and how to set foreign keys (in case of relational DBs).
json - Standard way of referencing an object by identity (for, eg, circular references)? - Stack Overflow
Are references possible in JSON?
I need to set a json object property in a object, then reference that property from another object in the same object
[JSON] Is it possible to self-reference values in a JSON declaration?
No, JSON is essentially represented as a string. Nodes JSON.stringify will attempt to convert 100 + this.armour to a primitive value (in this case NaN), but other implementations of stringifywould perhaps render it as a single string that when parsed would result in a string "100 + this.armour".
If I were you, I would store the stringified object only with values that can be represented as primitive values. Then, when you parse the JSON string into a JS object, pass it into a function that will compute the additional properties that rely on other properties.
More on reddit.comI was searching on this same feature recently. There does not seem to be a standard or ubiquitous implementation for referencing in JSON. I found a couple of resources that I can share:
- The Future for JSON Referencing
http://groups.google.com/group/json-schema/browse_thread/thread/95fb4006f1f92a40 - This is just a discussion on id-based referencing.
- JSON Referencing in Dojo
http://www.sitepen.com/blog/2008/06/17/json-referencing-in-dojo/ - An implementation in Dojox (extensions for the Dojo framework) - discusses id-based and path based referencing.
- JSONPath - XPath for JSON
http://goessner.net/articles/JsonPath/ - This seems to be an attempt at establishing a standard for path based JSON referencing - maybe a small subset of XPath (?). There seems to be an implementation here but I kept getting errors on the download section - you might have better luck. But again this is no where close to a standard yet.
There is the "JSON Reference" specification, but it seems it didn't got over the state of an expired Internet draft.
Still, it seems to be used in JSON Schema and Swagger (now OpenAPI) (for reusing parts of an API description in other places of the same or another API description).
A reference to an object in the same file looks like this: { "$ref": "#/definitions/Problem" }.
Old question but some possibly new answers like JSON Spec and JSON Reference https://json-spec.readthedocs.io/reference.html
[{
"name": "John",
},
{
"name" : "Jack",
"parent": {"$ref": "#/0"}
},
...
]
or possibly better with JSON Path syntax http://goessner.net/articles/JsonPath/
[{
"name": "John",
},
{
"name" : "Jack",
"parent": {"
.[?(@.name=='John')]"}
},
...
]
You can't. You can specify the path to the parent as a string and evaluate that at runtime, but as JSON is just strings, integers, arrays, and dictionaries, you can't use references.
what your trying to do is not possible.
the object has to be initialized before its values can be referred to
you could use a function inside the object.
or change the initial val of StAd0.src to '' or 'ar/55871' then reset that value after you set the var object; to object.StAd0.src = 'ar/55871'+ object.ext.sound;
var object = {
ext: {
sound: '.mp3'
},
pref: {
acc: 1
},
StAd0: {
from: 25,
to: 180,
src: 'ar/55871',
du: 5228
},
Image_33: {
type: 15,
from: 4,
to: 48,
rp: 0,
rpa: 0,
mdi: 'Image_33c',
trin: 6,
trout: 6,
ef: {}
},
Image_33c: {
b: [171, 259, 850, 360],
ip: 'dr/7029_679_101.png',
dn: 'Image_33',
visible: 1,
accstr: 'Image ',
vb: [171, 259, 850, 360]
}
};
object.StAd0.src = 'ar/55871'+ object.ext.sound;
Then src must be a function.
var object = {
ext: {
sound: '.mp3'
},
pref: {
acc: 1
},
StAd0: {
from: 25,
to: 180,
src: function() {
return 'ar/55871'+ this.ext.sound;
},
du: 5228
},
Image_33: {
type: 15,
from: 4,
to: 48,
rp: 0,
rpa: 0,
mdi: 'Image_33c',
trin: 6,
trout: 6,
ef: {}
},
Image_33c: {
b: [171, 259, 850, 360],
ip: 'dr/7029_679_101.png',
dn: 'Image_33',
visible: 1,
accstr: 'Image ',
vb: [171, 259, 850, 360]
}
}
But you must get src like this,
object.stAd0.src();
EDIT:
There isn't anyway to do it without a function, because if you try that like this,
src: ar/55871+ this.ext.sound;
that will work only once at parse-time. Than it will have a static value inside.
If you can't change all src properties to function, you can get it like this as well.
var src = (typeof object.StAd0.src == "function")? object.StAd0.src() : object.StAd0.src;
So If src is defined as a function, it will call it else will take it like a property.
Hey peeps,
Okay, so, just playing with making a wee CCG and storing the stats in a JSON object, but some of the stats are self-referential and I was wondering if there was a way around this. FOR EXAMPLE :
var cardOne = {
name : "Example Card",
armour : 70,
courage : 100 + this.armour
};Now, I know that this.armour won't work in this context, but what would?
Any help would be grand. Thanks in advance!
-P
EDIT 1: okay, seeing as this is Chrome-only project I've decided to take advantage of ES6's class notation and implement it like this :
class Card {
constructor(_name, _armour){
name = _name;
armour = _armour;
courage = 100 + _armour;
}
}
var testCard = new Card("Example Card", 70);...and that's how it'll stay for now, but if you can point me towards a more efficient alternative then that'd be great!
EDIT 2: as u/talmobi/ pointed out, this is the equivalent of simply writing :
var Card = function(_name, _armour){
this.name = _name;
this.armour = _armour;
this.courage = 100 + _armour;
};
var testCard = new Card("Example Card", 70);Well...that's not exactly what they said, but you can read their full comment here.
No, JSON is essentially represented as a string. Nodes JSON.stringify will attempt to convert 100 + this.armour to a primitive value (in this case NaN), but other implementations of stringifywould perhaps render it as a single string that when parsed would result in a string "100 + this.armour".
If I were you, I would store the stringified object only with values that can be represented as primitive values. Then, when you parse the JSON string into a JS object, pass it into a function that will compute the additional properties that rely on other properties.
ES6 class notation is just sugar... why didn't you use a constructor function from the start?
var Card = function (o) {
// when using "new" the fn implicityly creates "this = {}";
Object.assign(this, o); // copy vals from argument
this.courage = 100 + this.armor;
// when using "new" the fn implicitly returns "this"
};
// call the Card fn as a "constructor" with "new"
var cardOne = new Card({name: "example", armor: 70});
console.log(cardOne);