Why and when do we need to flatten JSON objects? - javascript

I am surprised that no one on StackOverflow asked this question before.
Looking through the JSON object documentation and a quick google search did not yield satisfactory results.
What's the advantage of it? How does it work?
Edit: To make it clear, take a look at this flatten/un-flatten example.
Fastest way to flatten / un-flatten nested JSON objects
Thank you.

There are many situations where you get JSON text that was automatically built by some library. Throughout the programming languages, there are many libraries that build JSON text (one example is here).
Whenever libraries add some additional object or array wrappings, you might want to get rid of them maybe because you send the JSON to the server and your code there crashes because it expects a primitive value instead of an object (or an array). Or, if your JSON is a server response, you don't want the resulting Javascript code having to differ between object/array or not object/array. In all these cases, flattening is helpful as it will save you time. You will have to implement lesser if/elses, and you can reliably expect your data structure to be as flat as possible.
The other approach to improve code for the scenario mentioned is to write the code in a maximal robust way so there is no way for it to crash by superfluous wrappings ever. So always expect some wrappers and get it's contents. Then, flattening is not needed.
You see, it depends on what is building the JSON and what is parsing it. The building may be out of your scope.
This leads also to data model questions. I've worked with XML code that needed to be parsed quiet a different way if there where 0 entries of some XY, or if there were >0 entries of some XY. Having a wrapper that is allowed to have 0 or more entries of some XY will make live easier. These are data model desicions.
In all cases where the JSON represents an object structure that I've combined manually, I expect it not to change. So flattening something I've designed in detail would be disturbing. Standard operations as far I've seen them do not need flattening (e.g. JSON.stringify(), json_encode() etc.)

Here's a simple scenario: In a web app you have an HTTP POST that is updating a complex relational object.
POST
update=1
&user.id=12345
&user.email=testmail#domain.tld
&user.profile.name=Mr. Test
&user.profile.age=42
&user.profile.friend.0.email=tom#domain.tld
&user.profile.friend.1.email=sally#domain.tld
&user.profile.friend.2.email=bob#domain.tld
&user.profile.skill.0.id=100
&user.profile.skill.0.name=javascript
&user.profile.skill.1.id=200
&user.profile.skill.1.name=piano
Everything is already in a flat structure, so why not have a simple one-to-one binding? If you had a list of constraints or security requirements that you needed to enforce you could validate them by searching directly on the sorted key list.
Flat structures are easier for people to understand and work with there's even some cross-over with database de-normalisation. It also allows for context specific security and constraints to be implemented in a readable, but more verbose way.
When showing a user's view in full you may want to hide the display of the primary key ID for the user's list of skills.
"user.profile.skill.#.id": { hidden: true, readonly: true }
But when looking directly at a skill (to possibly edit it as an administrator) you may want to see the ID.
"skill.id": { readonly: true }
If you were writing a user-centric/self-service type CMS application you'd get more users on board and able to contribute using a straightforward flat model (flat abstraction of the underlying nested relational model) than you would with just the nested model.
TLDR: Flat is easier to read than nested. While programmers can handle nested schemas, recursive parsing and processing; end-users and admins usually prefer that part abstracted away.

I realize this is a 5 year old question at this point, but I figured, I'd add my thoughts to it, in case someone runs into a similar use case and finds this useful.
One of the use cases why you would want to flatten a JSON object, is for dynamic template binding via Regular Expression (RegEx) string interpolation. Well wasn't that a mouthful 👀😅? It simply translates to "template filling a string without hardcoding".
Ok Imagine a scenario, you have a template string like this for an email:
Hello {{firstName}},
It is amazing you chose to join our site. We are happy to have you on board.
To get started, we would really love it if you can confirm your email address
by clicking on the link: {{confirm_url}}.
Welcome aboard
The Team!
Given the following JSON object in memory:
{
"user" : {
"prefix" : "Dr.",
"firstName" : "Awah",
"lastName" : "Teh",
"email" : "awah#superduperubercoolsite.com",
"address" : {
"street": "100 Main St",
"city" : "PleasantVille",
"state" : "NY",
"phone" : "+1-212-555-1212"
}
},
"meta" : {
"confirm_url" : "http://superduperubercoolsite.com/confirm/ABC123"
}
}
it seems super simple to do a Regular Expression replace like so (assuming our email template string was stored in a variable named template and the json object was stored in a variable called templateData:
template = template.replace(new RegExp('{{firstName}}', 'g'), templateData.user.firstName);
template = template.replace(new RegExp('{{confirm_url}}', 'g'), templateData.meta.confirm_url);
Easy right? --> Actually yes! How about this email had 10 templated fields, or you wanted to decouple the template from the code, by storing it in a separate system like SendGrid, where your cool head of marketing can access the template and make changes to the copy-language, without having to call someone from engineering to make changes to the code, test the code and redeploy to production (what a hassle).
This is exactly where flattening of the JSON comes save the day!
Now there are many ways to flatten JSON, I have attached a link to a codepen I wrote that has logic to flatten JSON (actually, I demonstrate two similar but different approaches in the methods flattenJSONIntoKVP and flattenJSONIntoRAW check 'em out!).
That said, there are other implementations out there, and it is worth remembering that the focus on this post is to discuss the WHY JSON flattening could be useful, not the HOW.
Moving on! Assume you flattened the JSON from above (using my implementation that results in key value pairs) to something like this:
[
{ "key": "user.prefix", "value": "Dr."},
{ "key": "user.firstName", "value": "Awah"},
{ "key": "user.lastName", "value": "Teh"},
{ "key": "user.email", "value": "awah#superduperubercoolsite.com"},
{ "key": "user.address.street", "value": "100 Main St"},
{ "key": "user.address.city", "value": "{PleasantVille"},
{ "key": "user.address.state", "value": "NY"},
{ "key": "user.address.phone", "value": "+1-212-555-1212"},
{ "key": "meta.confirm_url", "value": "http://superduperubercoolsite.com/confirm/ABC123"},
]
Now, my friend, you are cooking with GAS!
Why, cause now you can dynamically interpolate the template string with values from the JSON object without giving too much worry to the structure of the JSON (if it changes due to the application evolving, you don't have to also remember to come down here and change this interpolation code -- you simply just have to update the email template itself, which mind you, is on SendGrid [per this example]).
So how to do it you say?: Simple, iteratively. Let's assume that flattened from above was stored in a variable called flatJSON:
///Notice how I use Javascripts native string interpolation to create my RegExp
///Also note that I am replacing the dot (.) in my flattened JSON variable names with a double underscore (__), I only do this because my intended target is SendGrid, and I don't believe it likes dots in its template placeholders.
flatJSON.forEach(kvp=>template = template.replace(new RegExp(`{{${kvp.key.replace(/\./g, '__'}}}`, 'g'), kvp.value));
That's it, one line of code to replace possibly 10 or even hundreds or even thousands (ok.. maybe not thousands, but you get the point).
Ohh! almost forgot, we need to update our template string.
Notice how now, in our new templated string we can use a somewhat FQDN style variable to map back to our original JSON (Ideally if SendGrid supported dots in their template placeholders, this would look super sweet but alas, can't always win everything!😭.
Hello {{user__firstName}},
It is amazing you chose to join our site. We are happy to have you on board.
To get started, we would really love it if you can confirm your email address
by clicking on the link: {{meta__confirm_url}}.
Welcome aboard {{user__prefix}} {{user__lastName}}!
The Team!
Et Voila!
Just like that, we have accomplished some good here today; we have:
Answered the WHY of flattening JSON objects
We dibble-dabbled into the how, with the codepen example
And we even overviewed a use case where taking advantage of JSON flattening can help you write durable dynamic code, that evolves as your underlying object structures change -- and that doesn't require you to leverage the big bad ugly eval method (we can talk about big bad ugly eval on another post).

Related

Recieving high volume data in client browser using Jquery / JavaScript

I am in the process of making a WordPress based application where a student can take the examination on his web-browser. The questions will be randomly selected and served from the question bank stored in a WordPress CMS.
In this regard following is important to share:
-each examination can have as many as 100 multiple choice questions.
-Each question can have images, each choice can have associated images.
-since the examination is time bound I can not send request to server every time the student completes his question.
My query is :
How do I send the questions from the server:
-should I send the whole question set in one go and then have the Java Script parse all the questions and choices parsed at the client side
or
-should the client repeatedly request the questions from server in the background in the chunks of say 5 question each, for example. If this is better approach I am not sure how do I implement this. Any pointers?, please.
Or is there a third approach which I am not aware of.
Please advise for any comments and solutions for the problem.
Thanks in advance.
Depends on user's selection,send appropriate JSON data to client and render it dynamivally,but if you want to use XML then lets talk about it:
I should mention that this comparison is really from the perspective of using them in a browser with JavaScript. It's not the way either data format has to be used, and there are plenty of good parsers which will change the details to make what I'm saying not quite valid.
JSON is both more compact and (in my view) more readable - in transmission it can be "faster" simply because less data is transferred.
In parsing, it depends on your parser. A parser turning the code (be it JSON or XML) into a data structure (like a map) may benefit from the strict nature of XML (XML Schemas disambiguate the data structure nicely) - however in JSON the type of an item (String/Number/Nested JSON Object) can be inferred syntactically, e.g:
myJSON = {"age" : 12,
"name" : "Danielle"}
The parser doesn't need to be intelligent enough to realise that 12 represents a number, (and Danielle is a string like any other). So in javascript we can do:
anObject = JSON.parse(myJSON);
anObject.age === 12 // True
anObject.name == "Danielle" // True
anObject.age === "12" // False
In XML we'd have to do something like the following:
<person>
<age>12</age>
<name>Danielle</name>
</person>
(as an aside, this illustrates the point that XML is rather more verbose; a concern for data transmission). To use this data, we'd run it through a parser, then we'd have to call something like:
myObject = parseThatXMLPlease();
thePeople = myObject.getChildren("person");
thePerson = thePeople[0];
thePerson.getChildren("name")[0].value() == "Danielle" // True
thePerson.getChildren("age")[0].value() == "12" // True
Actually, a good parser might well type the age for you (on the other hand, you might well not want it to). What's going on when we access this data is - instead of doing an attribute lookup like in the JSON example above - we're doing a map lookup on the key name. It might be more intuitive to form the XML like this:
<person name="Danielle" age="12" />
But we'd still have to do map lookups to access our data:
myObject = parseThatXMLPlease();
age = myObject.getChildren("person")[0].getAttr("age");

Creating a short, decryptable URL with no back end

I'm creating a front-end React application which has no back-end logic. In this application, users can enter data into multiple form fields. I'm wanting to allow users to link directly to the application with their fields filled in based on data stored in the URL. The problem is, I don't know if there's a way of generating a nice looking URL with JavaScript alone.
Ideally I'm wanting the end-result to look something like this:
http://example.com/#/.../sdf098sdfipodfi0sf3j
...when the user loads up that URL, it should decrypt the string and restore the saved data (how resources like Codepen and JSFiddle allow linking directly to results, but without a back-end or database).
Here's an example of the data I have:
{
"Episodes": [
{
"Id":"1",
"Age":"25",
"SEX":"1",
"Diagnosis":["1","2","3","4","5","6","7","8","9","10"],
"Procedure":["1","2","3","4","5","6","7","8","9","10"]
}
]
}
There problem I'm having is that there can be:
Up to 250 Episodes.
Up to 999 Diagnoses and Procedures within each.
The above requirements are absolute extremes and for the most part there will probably only ever be around 5 or 6 Episodes each with around 10 Diagnoses and 4 or 5 Procedures.
If I stringify and then encode the JSON object and stick that in the URL, I'll end up with an incredibly ugly output riddled with % symbols:
http://example.com/#/.../%7B%22Episodes%22:%5B%7B%22Id%22:%221%22,%22Age%22:%2225%22,%22SEX%22:%221%22,%22Diagnosis%22:%5B%221%22,%222%22,%223%22,%224%22,%225%22,%226%22,%227%22,%228%22,%229%22,%2210%22%5D,%22Procedure%22:%5B%221%22,%222%22,%223%22,%224%22,%225%22,%226%22,%227%22,%228%22,%229%22,%2210%22%5D%7D%5D%7D
If I go further and convert that into Base64 using btoa, I get something which looks more like a shortened URL, but bearing in mind this is with the demo data I've provided above, this becomes way too long:
http://example.com/#/.../JTdCJTIyRXBpc29kZXMlMjI6JTVCJTdCJTIySWQlMjI6JTIyMSUyMiwlMjJBZ2UlMjI6JTIyMjUlMjIsJTIyU0VYJTIyOiUyMjElMjIsJTIyRGlhZ25vc2lzJTIyOiU1QiUyMjElMjIsJTIyMiUyMiwlMjIzJTIyLCUyMjQlMjIsJTIyNSUyMiwlMjI2JTIyLCUyMjclMjIsJTIyOCUyMiwlMjI5JTIyLCUyMjEwJTIyJTVELCUyMlByb2NlZHVyZSUyMjolNUIlMjIxJTIyLCUyMjIlMjIsJTIyMyUyMiwlMjI0JTIyLCUyMjUlMjIsJTIyNiUyMiwlMjI3JTIyLCUyMjglMjIsJTIyOSUyMiwlMjIxMCUyMiU1RCU3RCU1RCU3RA==
Is there a nicer way I can condense a lot of information into a relatively small string which would fit nicely in a URL, without any back-end logic?
Ideally I'm wanting a native JavaScript solution, but I appreciate that may not be possible.
How uniform is the data structure?
I can see that with the example you've given above:
{
"Episodes": [
{
"Id":"1",
"Age":"25",
"SEX":"1",
"Diagnosis":["1","2","3","4","5","6","7","8","9","10"],
"Procedure":["1","2","3","4","5","6","7","8","9","10"]
}
]
}
You could reconstruct that with:
http://example.com/#/.../E1I1A25S1D10P10
But that's still a 15-character shortcode for 1 episode... so if there were 6 episodes, that would increase to around 90 characters.

Parse Javascript To JSON Using Python 3

this is a very specific request, and for that i apologise, but i am at a loss for what to do..
for a javascript project i am working on i want to be able to parse javascript with python and i found this implementation`port of the original narcissus called pynarcissus:
https://github.com/jtolds/pynarcissus
the problem for me is the information is buried in the python class structure.. something with which i am only vaguely competent.. and i want the output to be in JSON
i have tried to mine the data out but each time the JSON is invalid
my question is how would you go about doing something like this? i'd appreciate any specifics because the project contains nested classes of disparate types creating what seems to be a wholly unique problem
here are my attempts:
i took the return value for parse() and created a function that descends through the class structure returning values based on their type: 'str', 'int', 'bool', 'NoneType', 'list', 'dict', 'main.Node', 'main.Tokenizer', 'main.Object'; but the returned object is missing some properties in the classes, ie 'type', while retaining others like 'type_', also tokenizer always contains the same values
i took the output of the str function that the program prints to stdout, removed the clear and copy functions and the tokenizer: [object Object], then tried to manually add in double quotes where necessary to make the output a valid JSON object.. a few problems here, first off ignoring the tokenizer object seems like i am missing out on vital information, and the other problem was that sometimes there is "value" : "{" and sometimes there is "value" : { .. }, after completing the work the JSON was invalid
assuming the issue lied in the "value" : { .. } issue i resolved to add a new function identical the the str function but instead of printing just %s values, it would print \"%s\" where necessary.. now, i could differentiate between "value": "{" and "value" : "{ .. }" but i would have to go through and manually remove the quotes around objects.. after doing so the JSON was invalid
i've tried every copy'pasta solution for python class to json from the stacks but the nested aspect of the classes along with the changing types add complexity.. some properties lack a .dict even when the type is "class 'dict'" so the one'method'fits'all lambda solutions fail
for posterity:
once i massaged the code of pynarcissus to print json i found that the process fails on nested functions.. hilariously exactly the reason i stepped away from my homebrew method
in another thread(i) #firstfire suggested esprima and pyesprima
so i looked into the esprima suggestions, and after a bit of 2to3`ing and some more work returning valid json i got it working and so far it fits my needs perfectly
check out the issue, pull request, and fork:
issues : https://github.com/int3/pyesprima/issues/1
pr : https://github.com/int3/pyesprima/pull/2
fork : https://github.com/ghissues/pyesprima
(i) http://www.linuxquestions.org/questi....php?p=5364199
the old answer::
closed the issue and added a pull request
https://github.com/jtolds/pynarcissus/issues/6
you can check out the fork if you got here by looking for a way to parse javascript to json in python 3
https://github.com/ghissues/pynarcissus

Better design for data stored using HTML5 localStorage

I have a scenario on my web application and I would like suggestions on how I could better design it.
I have to steps on my application: Collection and Analysis.
When there is a collection happening, the user needs to keep informed that this collection is going on, and the same with the analysis. The system also shows the 10 last collection and analysis performed by the user.
When the user is interacting with the system, the collections and analysis in progress (and, therefore, the last collections/analysis) keep changing very frequently. So, after considering different ways of storing these informations in order to display them properly, as they are so dynamic, I chose to use HTML5's localStorage, and I am doing everything with JavaScript.
Here is how they are stored:
Collection in Progress: (set by a function called addItem that receives ITEMNAME)
Key: c_ITEMNAME_Storage
Value: c_ITEMNAME
Collection Finished or Error: (set by a function called editItem that also receives ITEMNAME and changes the value of the corresponding key)
Key: c_ITEMNAME_Storage
Value: c_Finished_ITEMNAME or c_Error_ITEMNAME
Collection in the 10 last Collections (set by a function called addItemLastCollections that receives ITEMNAME and prepares the key with the current date and time)
Key: ORDERNUMBER_c_ITEMNAME_DATE_TIME
Value: c_ITEMNAME
Note: The order number is from 0 to 9, and when each collection finishes, it receives the number 0. At the same time, the number 9 is deleted when the addItemLastCollections function is called.
For the analysis is pretty much the same, the only thing that changes is that the "c" becomes an "a".
Anyway, I guess you understood the idea, but if anything is unclear, let me know.
What I want is opinions and suggestions of other approaches, as I am considering this inefficient and impractical, even though it is working fine. I want something easily maintained. I think that sticking with localStorage is probably the best, but not this way. I am not very familiar with the use of Design Patterns in JavaScript, although I use some of them very frequently in Java. If anyone can give me a hand with that, it would be good.
EDIT:
It is a bit hard even for me to explain exactly why I feel it is inefficient. I guess the main reason is because for each case (Progress, Finished, Error, Last Collections) I have to call a method and modify the String (adding underline and more information), and for me to access any data (let's say, the name or the date) of each one of them I need to test to see which case is it and then keep using split( _ ). I know this is not very straightforward but I guess that this whole approach could be better designed. As I am working alone on this part of the software, I don't have anyone that I can discuss things with, so I thought here would be a good place to exchange ideas :)
Thanks in advance!
Not exactly sure what you are looking for. Generally I use localStorage just to store stringified versions of objects that fit my application. Rather than setting up all sorts of different keys for each variable within localStore, I just dump stringified versions of my object into one key in localStorage. That way the data is the same structure whether it comes from server as JSON or I pull it from local.
You can quickly save or retrieve deeply nested objects/arrays using JSON.stringify( object) and JSON.parse( 'string from store');
Example:
My App Object as sent from server as JSON( I realize this isn't proper quoted JSON)
var data={ foo: {bar:[1,2,3], baz:[4,5,6,7]},
foo2: {bar:[1,2,3], baz:[4,5,6,7]}
}
saveObjLocal( 'app_analysis', data);
function saveObjLocal( key, obj){
localStorage.set( key, JSON.stringify(obj)
}
function getlocalObj( key){
return JSON.parse( localStorage.get(key) );
}
var analysisObj= =getlocalObj('app_analysis');
alert( analysisObj.foo.bar[2])

Console log from within json array

Just playing around with a JSON array and wanted to know if it was possible to console log from directly within a JSON array. ie:
{ "id": "1", "type": "text", "description": "hello <script>console.log('console this text')</script> I am testing },
In the above example it will display the <script>console.log('console this text')</script> as text rather than as actual html. Any way to make this work to produce the message in console by placing it within the array?
That really depends on what you mean...
In straight JavaScript, you can use object notation in that way, but you really need to wrap it in a function call.
In addition to this, you are mixing javascript and loose text very badly... you really need to let the browser know which one you are using and when.
For example, those script tags? If you are already using JavaScript, then why tell the browser 'here is some script'?
With a little cleaning up:
var myObject = {
id: "1",
type: "text",
description: function(){console.log('console this text')}
}
myObject.description();
This is valid JavaScript and will run perfectly well in a browser if entered into the page this way.
However, I suspect that this isn't what you mean... what you intend to do is to pull this from an AJAX call, for example, and have it run arbitrary script within a browser.
That will not work.
JSON, used this way, is designed as a data format, and does not allow methods to be passed, only properties.
However, there are some uses where this type of behavior could be coaxed: LOOK HERE.
In short, ANY text, JSON or not, could be evaluated on a client system and could potentially run malicious code. This is very similar to security issues in PHP where poor programming practice allows the use eval and other exploits to run client fed code on the server.
This is why so many websites are neurotic in their scrubbing of any data which has been fed by an arbitrary user... scrubbing html tags and javascript code out of user comments, for example.
You can try using a self invoking function.
var obj = {
'a' : '1',
'b' : '2',
'c' : (function(){console.log('3')})()
}

Categories