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

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

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.)

stringify in query-string module not working as expected in Jest tests

I'm writing a unit test in Jest.
In the unit under test I am importing
import queryString from 'query-string'
and it is executing the code:
queryString.stringify(ids)
where ids is an array in the following format:
[{ id: '123' },{ id: '321' }]
This code works perfectly when running in my deployed webpage, but in a JEST test it gives the following output:
id=%5Bobject%20Object%5D&id=%5Bobject%20Object%5D
whereas the same code in a browser gives:
id=123&id=321
As per the requisites of the query-string module, I am using a verison of node > 6.
I have also added:
/* jest commonjs */
to the top of my test file as query-string targets node.
Additionally I have tried setting various options in stringify but to no avail.
Can anyone tell me why I'm getting different results in these different environments and how I can get my test to work? i.e. not render the string as "%5Bobject%20".
Sure, I could implement my own stringify method, but this library is built to do this!
Can you please define what the expected behavior would be?
According to the documentation, stringify() converts an object into a query. Since you are passing ids, an array of elements, there are different possible behaviors you may get.
Please note that, in javascript, an array is an object with numbers as keys, so [ { id: '123' }, { id: '456' } ] actually looks like { '0': { 'id': '123' }, '1': { 'id': '456' } } (take a look at Object.keys of the array, you'll see it's ['0','1']).
So, that being said, what queryString is doing is converting each pair key-value into key=value, where both key and values have been "stringified" (I'm assuming through the String constructor). Since the value is an object, it returns that things you're seeing (indeed, String({}) is [object Object]. What I would expect (and I'm indeed getting) from the stringification of an array of objects is therefore something like 0=[object Object]&1=[object Object] (with the square brackets converted to %5B and %5D and spaces to %20).
I don't really know where that questionId is coming from, so a little more context should be provided (e.g. showing the actual object being stringified could be useful) but, to get to the point, in order to avoid having your object be converted to [object Object] you should use a key extractor, that returns the value you actually want to be shown as value.
So, for example, if your array is as described above and the result you'd like to get is 0=123&1=456, you would do something like:
const ids = [ {id: '123'}, {id: '456'} ];
queryString.stringify(ids.map(v => v.id))
Instead, if the expected behavior is id=123&id=456, you need to convert the array to the object { id: ['123','456'] }. You can do that with the following
const ids = [ {id: '123'}, {id: '456'} ];
queryString.stringify({ id: ids.reduce( (c,v) => c.concat(v.id), []) })
So, you need to transform your original ids array into an object that is suitable for stringify.
You can use this npm package https://www.npmjs.com/package/qs
It has a working qs.stringify

Ajax return array shows [object Object],[object Object] in PHP

Within Jquery I am creating two arrays, one embedded in the other, like so....
arrayOne = [{name:'a',value:1}, {name:'b',value:2}]
var arrayTwo = [{name:'foo',value:'blah'},{name:'arrayOne',value:arrayOne}];
I am then putting this though Ajax and extracting the variable via PHP on the other side. The results of a print_r($arrayTwo) are as follows...
Array([foo] => blah [arrayOne] => [object Object],[object Object])
I can see no way of extracting the contents of arrayOne, which is a pity because I really need them! Can anyone tell me what I am doing wrong in Jquery or what I need to do in PHP to make the embedded array accessible.
Many thanks as always
Edit to add my Ajax code....
$.ajax({
type: "POST",
url:'actions.php',
data:arrayTwo,
datatype:'json',
cache: false,
success: function(data){
}
})
The issue is that jQuery's $.ajax (or rather $.param) method treats an array of objects in a special way. jQuery will use name as the parameter name and the string representation of value as value:
> $.param([{name: 'foo', value: 42}, {name: 'bar', value: 21}])
"foo=42&bar=21"
But the string representation of arrayOne is the useless stuff you are seeing on the server:
> [{name:'a',value:1}, {name:'b',value:2}].toString()
"[object Object],[object Object]"
The documentation actually points out the caveats when passing an array / object:
If the object passed is in an Array, it must be an array of objects in the format returned by .serializeArray()
[
{ name: "first", value: "Rick" },
{ name: "last", value: "Astley" },
{ name: "job", value: "Rock Star" }
]
Note: Because some frameworks have limited ability to parse serialized arrays, developers should exercise caution when passing an obj argument that contains objects or arrays nested within another array.
Note: Because there is no universally agreed-upon specification for param strings, it is not possible to encode complex data structures using this method in a manner that works ideally across all languages supporting such input. Use JSON format as an alternative for encoding complex data instead.
Since you have a complex data structure, you should probably use JSON to encode your data:
data: {data: JSON.stringify(arrayTwo)},
and on the server you simply decode it with
$data = json_decode($_POST['data'], true);
$data will have the exact same structure as arrayTwo.
But in case you want to actually have parameters with names foo and arrayOne, then you only need to serialize the the value of arrayOne:
data: [
{name:'foo',value:'blah'},
{name:'arrayOne',value: JSON.stringify(arrayOne)}
],
and in PHP:
$arrayOne = json_decode($_POST['arrayOne'], true);

Hash of hash of list of lists in javascript

I'm a perl programmer learning javascript. In perl, I would frequently use hashes to create 'data structures' from data returned from a database query. For example, I would build hashes like this:
*loop through list of data*
push(#{$hash{$key1}{$key2}}, [$value1, $value2, $value3, $value4]);
*endloop*
this would add a reference to the list of four values to a list in the hash (with multiple keys).
I'm having a hard time finding information on how I would implement a similar structure in javascript. My goal is to read in a JSON file that has a list of objects (which has no particular order) and turn it into a hash so it can be sorted by the keys and then display it in an HTML table.
Perhaps this is the wrong way to think about this problem and javascript will have a different approach. I'd like to know if what I'm trying to do is possible, the code to create the hash, and the code to access the hash.
Thanks,
Rob
This is my straight translation, tested at the Google Chrome console prompt >
> hash = {}
Object {}
> hash["key1"] = {}
Object {}
> hash["key1"]["key2"] = []
[]
> hash["key1"]["key2"].push([ 'value1', 'value2', 'value3', 'value4'])
1
> hash
Object {key1: Object}
> JSON.stringify(hash, null, 2)
"{
"key1": {
"key2": [
[
"value1",
"value2",
"value3",
"value4"
]
]
}
}"
Hash in Perl is just set of key/value pairs. Javascript has similar data structure - Objects. You could do what you want
> a = {}
{}
> a.res = []
[]
> a.res.push([1,2,3])
1
> a.res.push([3,"sd",1])
2
> a
{ res:
[ [ 1, 2, 3 ],
[ 3, 'sd', 1 ] ] }
Javascript does not have an ordered hash and a lookup with multiple keys. You can use the properties of an object to create a lookup by a single unique key and you can then build on that notion as needed. See this answer for an idea how to implement a simple form of hash or set in javascript.
The basic idea is that you create an object and then add key/value pairs to it:
var myLookup = {};
myLookup[key1] = value1;
myLookup[key2] = value2;
Then, you can look up a value by the key:
console.log(myLookup[key1]); // shows value1
If you want more specific help, you will have to be more specific in your question. Show us what the JSON you start with and describe exactly how you want to be able to access it so we can figure out what type of JS data structure makes the most sense to put it in. Remember, once the JSON is parsed, it is already in a javascript data structure at that point so the it becomes a question of what kind of access you need to make to the data to understand whether the data should be restructured with certain key lookups?
It is generally best to concentrate on problem/solution and NOT on trying to do something the same way another language does it.

Array stored in Mongo fails deep assert comparison to native javascript array with same length and values

I have a field in mongo defined with the mongoose ORM like so:
state: {type: [Number], required: true }
If I take a peek at a sample document with the mongo console, state looks like
state: [ 1, 1, 1 ]
So far, so good. But strange enough for that same document the following assert fails:
assert.deepEqual state, [ 1, 1, 1 ]
Can't figure out if this is something I'm missing with object comparisons in JS or something to do with the way mongo is returning the state array.
MongoDB has a bug where properties that should be non-enumerable are enumerated:
Eg, an array whose values are:
[ '0', '1']
has the following keys, according to Object.keys():
[ '0', '1', '_atomics', 'validators', '_path', '_parent', '_schema' ]
Note Mongo now uses V8, which supports ES5, which has had the ability to create non-enumerable properties via Object.defineProperty() for many, many years.
As the other poster mentions:
var fixMongoArray = function(array) {
return Array.prototype.slice.call(array)
}

Categories

Resources