JSON object being reordered by Javascript - javascript

I have a rather large JSON object being generated via PHP. It creates a PHP object out of a database, with keys that are integers, ie 1-100. These keys are not in that order though, they are in a random order, such as 55, 72, 5, 8, 14, 32, 64, etc. I then use json_encode to output the object as JSON. I then use an AJAX call to grab that JSON and store it in a variable. However, that variable has the JSON object in order 1-100, instead of the sorted order above.
Any ideas why it's doing that, and how I can fix it?

JSON objects have no specific order and are not guaranteed to keep the order you put things in. If you want keys in an order, you should put them in an array which will maintain order. If you want an ordered set of key/value pairs, you can use several different forms.
The simplest would be to just have a single array that is an alternating set of key, value:
var data = ["key1", "value1", "key2", "value2",...];
Or, you could do an array of objects:
var data = [{key: "key1", data: "value1"}, {key: "key2", data: "value2"}, {...}]

Keys within an object aren't technically ordered. That you expect them to be in a particular order is a mistake in data structure. A JSON parser will interpret numerical keys as array positions.
this
{
55: "foo",
29: "bar",
...
}
is semantically the same as:
object[55] = "foo"
object[29] = "bar"
which is:
[
...
"bar" //index 29
...
"foo" //index 55
...
]
Instead, you should separate the order and the identify of your objects:
[
{id: 55, content: "foo"},
{id: 29, content: "bar"},
...
]

Related

Create Json with specific structure from two different arrays in javascript

I've already tried to find a solution on stack, but I didn't found a possible reply, so I decided to open a topic to ask:
Let's say we have 2 arrays: one containing "keys" and another one containing "values"
Example:
keys = [CO2, Blood, General, AnotherKey, ... ]
values = [[2,5,4,6],[4,5,6],[1,3,34.5,43.4],[... [
I have to create a Json with a specific structure like:
[{
name: 'CO2',
data: [2,5,4,6]
}, {
name: 'Blood',
data: [4,5,6]
}, {
name: 'General',
data: [1,3,34.5,43.4]
}, {
...
},
}]
I've tried to make some test bymyself, like concatenate strings and then encode it as json, but I don't think is the correct path to follow and a good implementation of it ... I've also take a look on JSON.PARSE, JSON.stringify, but I never arrived at good solution so... I am asking if someone know the correct way to implements it!
EDIT:
In reality, i didn't find a solution since "name" and "data" are no strings but object
Here's one way to get your desired output:
keys = ["CO2", "Blood", "General", "AnotherKey"]
values = [[2,5,4,6],[4,5,6],[1,3,34.5,43.4],[0] ]
const output = keys.map((x, i) => {
return {"name": x, "data": values[i]}
})
console.log(output)
However, since you're literally constructing key/value pairs, you should consider whether an object might be a better data format to output:
keys = ["CO2", "Blood", "General", "AnotherKey"]
values = [[2,5,4,6],[4,5,6],[1,3,34.5,43.4],[0] ]
const output = {}
for (let i=0; i<keys.length; i++) {
output[keys[i]] = values[i]
}
console.log(output)
With this data structure you can easily get the data for any keyword (e.g. output.CO2). With your array structure you would need to iterate over the array every time you wanted to find something in it.
(Note: The reason you weren't getting anywhere useful by searching for JSON methods is that nothing in your question has anything to do with JSON; you're just trying to transform some data from one format to another. JSON is a string representation of a data object.)

Delicate data manipulation within a javascript object of single-value arrays

I have a unique problem that I am trying to solve with some complex javascript code. For your information I am using MongoDB, NodeJS, ExpressJS, and VueJS as my technology stack.
I am writing an application that makes api calls to an outside partner of mine that is returning a huge xml based data file. (Unfortunately they are incapable of sending JSON data). After I receive the data from them, I run it through the parseString command of the xml2js library. But the way that it sends the code back is really really strange. From the outside it looks fine, it's an array of objects: [ {object1},{object2},....{objectN} ]. but when you look at the individual objects, it formats the data strangely:
object1 = {
key1: [ 'string' ],
key2: [ '01234657' ],
key3: [ 'email#email.com' ],
key4: [{
key5: [ '8372655573' ],
key6: [ '25.00' ],
key7: [ 'description of item purchased' ]
}],
key8: [ 'otherData' ],
// .......and so on until
NthKey: [ 'dataType' ]
}
I anticipated that the majority of the data I was going to receive was going to consist of single key to single data value pairs, with a few exceptions. But for every single key of the returned object from parseString they assign the value to an array as a string, no matter what. And for the times that a key has a bunch of different data types entered into it (such as with key4 in the example above), I have to dig down into not only an array, but also a nested object inside that array, and into the individual keys that are associated with my data.....
I find that really strange and difficult to work with because now I have to create a bunch of loops that go through and create basically a carbon copy of object 1 except that it looks like this:
object1CarbonCopy = {
key1: String,
key2: Number,
key3: email,
key4: {
key5: Number,
key6: Number,
key7: String
},
key8: String
// and so on until........
NthKey: 'dataType'
}
Do any of you have advice on code that could accomplish this? or if there are settings/options that I can pass into xml2js to change how it spits out the data? Any advice at all would be very appreciated.
So I learned a valuable lesson today, sometimes you need to read through the docs multiple times because you miss things. It turns out that there is an option that turns off that automatic array inserting junk:
parser = new xml2js.Parser( {explicitArray: false} );
If you are viewing this question and don't know what the problem is, pass {explicitArray: false} as a parameter to your Parser constructor

Multiple objects inside main object cannot be sorted by key value, but objects inside an array can be - how and why does this happen?

This is a follow up to a previous question I asked:
Sort JSON response by key value
So I know that objects cannot be sorted using the .sort method and if I push each object into an array, I can sort it the way I want.
Why does .sort not work on this:
{ A:{...}, B:{...}, C:{...} }
but works on this:
[ {...}, {...}, {...} ]
It's still accessing and working with object properties in both examples, right?
Here's some code:
var query = {
"736":{
ns: 42,
pageid: 12,
lang: "en",
index: 3
},
"421":{
ns: 12,
pageid: 36,
lang: "en",
index: 4
},
"102":{
ns: 2,
pageid: 19,
lang: "en",
index: 1
}
};
var queryArr = [{ns: 42, pageid: 12, lang: "en", index: 3}, {ns: 12, pageid: 36, lang: "en", index: 4}, {ns: 2, pageid: 19, lang: "en", index: 1}];
query is an object with multiple objects in it, and queryArr is an arry with multiple objects in it. If I wanted to sort query by its index key's value, I'd have to convert it to an arry first, and then run .sort on that array, correct?
What I want to know is why. What prevents query from being sorted, but allows the objects inside queryArr to be sorted? They're both still objects right? The only difference is the outer body is an object in the first, and an array in the second - but it's still working with objects when sorting.
My sort function still referneces the index using the object property accessor:
queryArr.sort(function(i,j){
return j.index - i.index;
});
Array object is object where the positive integer keys are used:
a = [, 1]
a[.1] = .1
a[-1] = -1
console.log( a )
console.log( { ...a } )
If the order of the properties can't be guaranteed, then for example array object [0, 1] can be stored as { "0": 0, "1": 1 } or { "1": 1, "0": 0 }.
Most array looping constructs will look for the "0" property before the "1" property, so the property order doesn't really matter.
Sorting array doesn't change it's properties order, but swaps the values associated with the properties.
Arrays are a special way of sequentially storing data. In the earliest implementations, this would be done by actually storing the array objects sequentially in memory. And resorting would actually physically move the objects in memory. So in your example where you have indices 102, 421, and 736. If you translated this to an array, you would actually have an array of length 737. 0 to 101 would be undefined, then you would have your object at 102. 103 to 420 would be undefined, then object 421. Et cetera.
Good to note that in your example when you translated your object into an array, you lost your keys (102, 421, 736). They simply became (0,1,2). In your example maybe this was okay, but if you had an object with properties like width, height, length, having these replaced with simple array indices like 0,1,2 would be a pretty significant loss of information.
Objects don't work the same way at all. They are not designed to store data sequentially, but hierarchically. So you can have a key 102 that points to an object, but you don't have to have keys 0-101. And key 102 doesn't designate the "order" of the item. It's just a name, and it could just as easily be length or fred or green as 102.
This mirrors reality. For example you might have an array to store a group of people, perhaps starting in order of age. And you could re-sort the list by different properties, like alphabetical by last name, or by height, etc.
But if we look at the objects within that array, it really makes no sense to talk about the order of firstName, lastName, height, weight, age, etc. There isn't really any "order" to speak of: weight doesn't have to come before height, or vice versa. And some people may like to see Last,First, while others prefer First Last. These properties are things we mostly want to be able to access directly by name, so an array isn't really ideal. We want named properties. Hence an object. Don't be confused just because you chose numbers as your property names...they're still names, not indices.
However it is of course possible to iterate all the properties of an object, and it is even possible to control the order in which you iterate them. Traditionally in javascript this iteration was done with the for...in syntax, which goes all the way back to es1. But you couldn't control the order in which the object's keys were iterated. To control order we would have to use for...in to populate an array of keys, then sort the array, then re-loop over the array.
However, it is possible in the newer es6 javascript world to iterate in some great new ways. For example, you can use Object.keys() to get an array of all the object keys (property names), and then you could sort this array. Saves the step of populating an array with for...in.
Another more advanced possibility in es6 (which uses Object.keys) is to actually make the object itself iterable by adding a Symbol.iterator. Again, this only works in es6+.
However the Symbol.iterator gives you a lot of power. This is what it looks like:
query[Symbol.iterator] = function*() {
let properties = Object.keys(this).sort();
for(let p of properties) {
yield {key:p, value:this[p]}
}
}
Once you add this iterator to the object, now you can use things like for...of. And in this example I added a .sort(), so this would iterate over the object's properties in ascending numeric order by key: 102, 421, 736. And since we are yielding an object with key and value, we are still able to see the key value, which we would NOT have if we had just translated to an array.
for(let {key,value} of query) {
console.log(key);
}

For loop for key/value pairs when key is numeric

I just realized I am having a malfunction in my overall web app and it's coming down to a for loop that is reordering my object/array.
I am retrieving an associative array (object) via AJAX. I can check it's structure upon return and it is correct. For example:
48 => Value1
50 => Value2
49 => Value3
51 => Value4
But, when I loop through it, the for loop reorders the object. This is because the assoc keys are numeric. They represent numeric IDs froma database. I didn't know javascript would choke on them and try to turn them into basic array keys in numeric order. So, it spits out as:
48 => Value1
49 => Value3
50 => Value2
51 => Value4
How can I loop through the object in the order I build it in? Do I have to build the object with strings as keys? Like "ID22" replacing 22. Or is there some way to force javascript to loop in a specific order?
Thanks!
Matt
There is no way to iterate JavaScript object in specific order, because JS object is unordered.
The best way to solve this problem - create 1 object and one array to keep order:
var values = {
48: "Value1"
50: "Value2"
49: "Value3"
51: "Value4"
}
var order = [48, 50, 49, 51] //put proterty id here to keep order eg. [51, 50, 49, 48]
This is only really a problem with Chrome, they have a bug for it but it's a "Won't Fix" for the sake of internal efficiencies.
The best way I've found to get around this problem is to changing using an object:
{
48: "Value1"
50: "Value2"
49: "Value3"
51: "Value4"
}
to instead an array like so:
[
{id: 48, value: "Value1"},
{id: 50, value: "Value2"},
{id: 49, value: "Value3"},
{id: 51, value: "Value4"}
]
It ends up being much more clean than the alternative workaround (which is as you originally suggested)
I believe you're using for…in to retrieve your key and value.
As the link above says, and as it's specified in ECMAScript specs, "The mechanics and order of enumerating the properties (step 6.a in the first algorithm, step 7.a in the second) is not specified."
It means, you can't rely at all on the order you will get via for…in or Object.keys. If the order is important to you, you have to store the order's index somewhere, and sort the data by that property. You can't use a mere Object like that.

javascript objects vs arrays vs JSON

Despite much googling and hair-pulling, I can't for the life of me articulate the difference between json, objects, and arrays (in javascript). Below is how I've been using 2-dimensional data containers (afraid to use the words "array," "object," or "json" here). Please tell me what these two examples are?
//first example:
[
{"record_id":1,"name":"Frank"},
{"record_id":2,"name":"Sally"}
]
//second example:
{
"countries":
[
{"id":1,"name":"Canada"},
{"id":2,"name":"Mexico"}
],
"states":
[
"id":1,"name":"Maine"},
{"id":2,"name":"Alaska"}
]
}
JSON is a representation of the data structure, it's not an object or an array.
[1,2,3]
is an array.
{"foo":"bar"}
is an object.
In your example,
[
{"record_id":1,"name":"Frank"},
{"record_id":2,"name":"Sally"}
]
Is an array of objects.
{
"countries":
[
{"id":1,"name":"Canada"},
{"id":2,"name":"Mexico"}
],
"states":
[
{"id":1,"name":"Maine"},
{"id":2,"name":"Alaska"}
]
}
Is an object containing other arrays and objects inside of it.
JSON is JavaScript Object Notation. This is simply a way of writing down JavaScript data types. It is not a data type in-and-of-itself.
See below for some examples of JavaScript data types, and the literal notation of creating them.
JSON can be used to send data from the server to the browser, for example, because it is easy for JavaScript to parse into a normal JavaScript data structure.
In your example, you are using lists of objects, and objects of objects.
This is a list of 3 empty objects.
[{}, {}, {}]
This is a list of three simple records:
var mylist = [
{name: 'John', age: 24},
{name: 'Bill', age: 42},
{name: 'Jill', age: 18},
]
You can access it like this:
mylist[1].name
>>> 'Bill'
mylist[2].age
>>> 18
JavaScript has several data types:
Number
1
100
-2000
123.45
String
"Hi John"
"Message:\nGo Forth"
Boolean
true
false
Array
[1,2,3]
[]
["a", "b", 123]
["a", "b", 123, [3,4,5]]
Object
{}
{a: 10}
{mylist: [1,2,3], yourlist: [4,5,6]}
{myself: {name: 'me', age: 10}, yourself: {name: 'you', age: 20}}
You use { braces } to declare an object literal.
You use [ square brackets ] to declare an array literal.
Objects are collections of key name value pairs.
Here's an example of an array of strings:
var a = [ "one", "two", "three" ];
Here's an example of a simple object that represents a person:
var personObject = {
name: 'Joe',
age: 25,
hometown: 'New York'
};
JSON is a textual data interchange format. As its name ("JavaScript Object Notation") suggests, it originates from JS; meaning that JSON is actually syntactically valid JavaScript. In other words, you can paste a JSON string directly into your JS code.
Arrays are special Objects. They can be constructed by [].
Objects can be constructed via {}.
So what you have in your example is two JSON strings, one representing an Array of objects, the second one representing an Object whose properties are themselves Arrays of Objects.
Well i believe objects can have methods and properties while arrays cant. JSON can be passed to the server while array cant be, unless you pass it as a string by POST

Categories

Resources