Dynamically create a nested JavaScript object with unknown keys - javascript

Let's say I have two arrays which are returned in a response from a REST call. For simplification I defined them hard-coded as keys and subKeys in the following example code.
From these arrays I'd like to create a nested object which, when outputted as a JSON string, looks like this:
Target JSON
{
"key1": {
"subKey1": "someValue"
},
"key2": {
"subKey2": "someValue"
},
"key3": {
"subKey3": "someValue"
}
}
Code sample
var keys = ["key1", "key2", "key3"]; // These come from a REST response
var subKeys = ["subKey1", "subKey2", "subKey3"]; // These come from a REST response
var targetObj = {}
for (const key in keys) {
targetObj[key] = {}
for (const subKey in subKeys) {
targetObj[key][subKey] = "someValue";
}
}
console.log(JSON.stringify(targetObj, null, 2));
While this gives me the correct behavior in my application I have the impression that there might be simpler approaches to achieve the same result, either in "vanilla" JavaScript or ES6? What bothers me here is that I define an empty object in each run of the for loop.

Your code does not produce the example output you said you want. It will put all 3 subkeys under each key, not one per key. Also you end up with numeric keys, not the key names.
var keys = ["key1", "key2", "key3"]; // These come from a REST response
var subKeys = ["subKey1", "subKey2", "subKey3"]; // These come from a REST response
var targetObj = {}
for (let i=0; i<keys.length; i++) {
const key = keys[i];
targetObj[key] = { [subKeys[i]]: "someValue" };
}
console.log(JSON.stringify(targetObj, null, 2));
First you were using "in" instead of "of" in the for-loop, and secondly you were not using the same index to find the subkey.
To avoid creating an empty object you can use this syntax:
{ [variable]: "value" }
This creates the object with the variable value as the key, and a string as the value. Putting the variable name in square brackets tells it to use the variable value rather than its name. Saying { variable: "value" } wouldn't work because the key would be "variable" not the value of variable.

Just use Array.prototype.reduce method:
const keys = ["key1", "key2", "key3"];
const subKeys = ["subKey1", "subKey2", "subKey3"];
const result = keys.reduce((acc, key, index) =>
({ ...acc, [key]: { [subKeys[index]]: 'someValue' } })
, {});
Note, this works only if keys and subKeys arrays are synced and their indexes are consistent with each other.

Related

Assigning K,V pairs to a JSON object in NodeJS

I have a NodeJS script that takes data from a source in the form of "key, value" pairs, and I would like to put that data into a JSON object.
I am using SNMP to get the k, v pairs, where the key is the OID. I would like to then map those values onto a JSON object without having to iteratively check each OID against a known value.
The k,v pairs are stored in objects as such, and I have no flexibility over this incoming data.
let pair = {
key: "abc...",
value: "xyz..."
}
I have defined the JSON object as an empty structure.
let jsonObject = {
ipaddress: "",
network: {
uptime: "",
throughput: "",
devices: ""
}
}
And I iterate through my keys (pairs is the name of an array containing the k,v objects)
for (let i = 0; i < pairs.length; i++) {
if (pairs[i].key == "1.2.3.4.5.6.7") jsonObject.ipaddress = pairs[i].value;
if (pairs[i].key == "2.3.4.5.6.7.8") jsonObject.network.uptime = pairs[i].value;
if (pairs[i].key == "3.4.5.6.7.8.9") jsonObject.network.devices = pairs[i].value;
}
I would like to know if there is any way to simplify this, as I have around 200 keys to process (the above code is simply an example), and it doesn't seem particularly well optimised for me to iterate over every possible key.
EDIT: The jsonObject is a lot more complex than shown here, with lots of layers and the names of the keys do not match up 1:1 with the json object property names as shown.
EDIT 2: This seems like an odd situation, I know.
For example, I want to take the K,V input:
Key Value
1.2.3.4.5.6 "10.0.0.1"
2.3.4.5.6.7 "3 Days 14 Hours 32 Minutes"
3.4.5.6.7.8 "1.1.1.1"
And convert it to a dissimilarly named JSON object
{
uptime: "3 Days 14 Hours 32 Minutes",
networking: {
ip: "10.0.0.1",
dns: "1.1.1.1"
}
}
Potentially using some form of mapping, instead of using ~200 if statements
Use the Array.prototype.reduce function.
const { name, ...properties } = pairs.reduce(
(obj, { key, value }) => Object.assign(obj, { [key]: value }),
{}
)
const obj = { name, properties }
Reduce will reduce an array into a scalar, in this case an object with all k,v pairs as fields with values on an object, starting with {} as a default value the merging each k,v pair 1 at a time.
Object.assign will merge objects, overwriting objects on the left with the fields of keys of objects on the right.
And finally the syntax to dynamically add a key on an object literal is { [k]: v }
By the way this is a useful trick for reducing the complexity of algorithms where you need to look up values in an array in a loop. Simply create an index of one array then in the loop, lookup in the index instead.
You can use Array.prototype.forEach for iterating and assigning the object.
const jsonObject = {
name: '',
properties: {
email: '',
address: '',
town: ''
}
};
const pairs = [{key: 'name', value: 'thatsimplekid'},
{key: 'email', value: 'aaa#domain.com'},
{key: 'town', value: 'myTown'},
{key: 'address', value:'123 main st' }];
pairs.forEach( ({key, value}) =>
jsonObject.hasOwnProperty(key) ?
jsonObject[key] = value :
jsonObject.properties[key] = value);
console.log(jsonObject);
for (let i = 0; i < pairs.length; i++) {
const key = pairs[i].key;
const value = pairs[i].value;
if (pairs[i].key == "name") {
jsonObject[key] = value;
} else {
jsonObject.properties[key] = value;
}
}
After the 'name' all values goes to the properties object, so a simple if would do it

How to access a String key in a javascript array of objects?

For example, the array is:
chipsArray = [{'cheetos':'good'},{'dorritos':'better'}]
Here, chipsArray[0] would give me {'cheetos':'good'}. Let's say I populated this array like the following:
chipsArray.push({[chips]:quality})
But now that I'm trying to access the cheetos or dorritos keys in each of objects in this array, I can't. Doing chipsArray[0].chips gives me undefined.
As far as I know when populating the key of an object with a certain value/variable, they should be wrapped in square braces. But how can we extract values from them later on when each of these objects are array indices like the example given above? I tried using Object.keys(chipsArray[index]), but this only gives me the keys whereas I'm trying to extract the specific value for that specific key.
Tl;Dr: How to extract the key of an object inside an array when the keys are strings like this:
chipsArray = [{'cheetos':'good'},{'dorritos':'better'}]
You could use Object.keys and get only the first element.
var chipsArray = [{ cheetos: 'good' }, { dorritos: 'better' }];
chipsArray.forEach(function (object) {
var key = Object.keys(object)[0];
console.log(key, object[key]);
});
Or create an object with the reference to the single objects
var chipsArray = [{ cheetos: 'good' }, { dorritos: 'better' }],
hash = Object.create(null);
chipsArray.forEach(function (object) {
hash[Object.keys(object)[0]] = object;
});
console.log(hash['dorritos']['dorritos']);
Use the following function. It returns the value by key in the array
function getItemByKey (key, array) {
var value;
array.some(function (obj) {
if (obj[key]) {
value = obj[key];
return true;
}
return false;
});
return value;
}
More about Array.prototype.some here
I think the easiest way is to access the value:
Object.values(chipsArray[i])
where i is the index of the array.
Output:
> chipsArray = [{'cheetos':'good'},{'dorritos':'better'}]
[ { cheetos: 'good' }, { dorritos: 'better' } ]
> Object.values(chipsArray[0])
[ 'good' ]

Extract only values from JSON object in javascript without using a loop

is there a "Nice" way to get all the values out of a json object (I don't care about the keys) - just get the values into array,
without using a loop ?
(lang is Javascript)
It depends on how you define "loop".
You can extract the properties with Object.keys and then map them to their values.
… it's still essentially a loop under the hood though.
var json = `{ "foo": 1, "bar": 2, "baz": 3 }`;
var obj = JSON.parse(json);
var values = Object.keys(obj).map(function (key) { return obj[key]; });
console.log(values);
With weaker browser support you could use the values method.
var json = `{ "foo": 1, "bar": 2, "baz": 3 }`;
var obj = JSON.parse(json);
var values = Object.values(obj);
console.log(values);
I think you are looking for Object.values() function, just pass the object to the values method of Object as first param. That's it!
Object.values({something: 'lol'});
> ["lol"]
Recursively extract as text
Yes, this is a loop but the underlying methods you are calling such as Object.values or arr.map are still loops. I found this useful for extracting text out of a json object for full text search in particular and thought it useful as I came here initially needing this but the answers only touched the surface as json is recursive in nature.
function textFromJson(json) {
if (json === null || json === undefined) {
return '';
}
if (!Array.isArray(json) && !Object.getPrototypeOf(json).isPrototypeOf(Object)) {
return '' + json;
}
const obj = {};
for (const key of Object.keys(json)) {
obj[key] = textFromJson(json[key]);
}
return Object.values(obj).join(' ');
}
With ES2017 you have Object.values(). You can polyfill it also.
Only you need is transform JSON to JavaScript object and call Object.values(). The result is an array of values.
var obj = JSON.parse(jsonData);
var result = Object.values(obj);
If you pass a function to JSON.parse, it will be called each time a value is parsed:
function get_values(json) {
let values = []
JSON.parse(json, (key,value)=>{ values.push(value) })
return values
}
ex:
get_values(`{"a":1, "b":[true, false], "c":3}`)
// returns a list of:
• 1
• true
• false
• [true, false]
• 3
• {a:1, b:[true, false], c:3}
Note: If you don't consider the full object to be a "value", just remove the last item.

Sort javascript key/value pairs inside object

I have some problem with sorting items inside object. So I have something like this:
var someObject = {
'type1': 'abc',
'type2': 'gty',
'type3': 'qwe',
'type4': 'bbvdd',
'type5': 'zxczvdf'
};
I want to sort someObject by value, and this is where I have problem.
I have sorting function that should return key/value pairs sorted by value:
function SortObject(passedObject) {
var values = [];
var sorted_obj = {};
for (var key in passedObject) {
if (passedObject.hasOwnProperty(key)) {
values.push(passedObject[key]);
}
}
// sort keys
values.sort();
// create new object based on Sorted Keys
jQuery.each(values, function (i, value) {
var key = GetKey(passedObject, value);
sorted_obj[key] = value;
});
return sorted_obj;
}
and function to get key:
function GetKey(someObject, value) {
for (var key in someObject) {
if (someObject[key] === value) {
return key;
}
}
}
The problem is in last part when creating new, returning object - it's sorted by key again. Why? And this is specific situation when i have to operate on object NOT on array (yes I know that would be easier...)
Does anyone know how to sort items in object?
Plain objects don't have order at all. Arrays -that are a special types of objects- have.
The most close thing that you can have is an array with the object values sorted . Something like, for example:
_valuesOfAnObjectSorted = Object.keys(object).map(function(k){ return object[k]; }).sort();
You have two possibilities:
Refactor your object into an array
Something like this:
var myObj = [
['type1', 'abc'],
['type2', 'gty'],
...
];
Or even better, since using it somewhere would not rely on array positions but full named keys:
var myObj = [
{name: 'type1', val:'abc'},
{name: 'type2', val:'gty'},
...
];
Use your object with an auxiliar array
Wherever you want to use your object ordered by the keys, you can extract the keys as an array, order it and traverse it to access the object
var ordKeys = Object.keys(myObj).sort(); // pass inside a function if you want specific order
var key;
for (var i = 0, len = ordKeys.length; i < len; i +=1) {
key = ordKeys[i]
alert(key + " - " + myObj[key]);
}
Combination of both of them
If the object is not constructed by you, but comes from somewhere else, you can use the second option approach to construct an array of objects as in the first option. That would let you use your array anywhere with perfect order.
EDIT
You might want to check the library underscore.js. There you have extremely useful methods that could do the trick pretty easily. Probably the method _.pairs with some mapping would do all the work in one statement.

Delete entries from an associative array (JavaScript)

I currently have a problem in deleting entries from an associative array in JS.
I tried this:
myArray['key'] = value;
myArray['key1'] = value1;
...
delete myArray['key'];
But I get following results in my application:
[ undefined, { key1: 'value1', key2: 'value2' }, undefined,
{ key1: 'value1', key2: 'value2' }, undefined, undefined ]
How can I delete the whole entry, key and value? I found the method splice() but I think it uses a different index. I wasn't able to delete the entries I want by passing the key to splice().
It seems you are mixing arrays and objects. Associative arrays should be realized with objects:
myArray = {};
myArray['key'] = value;
myArray['key1'] = value1;
It is a bit confusing though because in your output, the objects don't have key anymore (so it worked), but the array containing those objects as undefined values. I cannot see how
delete myArray['key']; is related to your output and which variable now contains which value (please clarify).
But it looks like you did something like:
var container = new Array(6);
container[1] = myArray;
container[3] = myArray;
This will initialize the array with 6 undefined values (sort of) and then set the second and forth value to something else.
If you want to use that "array" as associative array, you should declare it as object too:
var container = {};
Please post more code if you need a better answer.
Update: Yes, you should declare displayedWidgets as object:
var widgets = {
displayedWidgets: {},
clear: function() {
this.displayedWidgets = {};
},
add: function(widget) {
this.displayedWidgets[widget.id] = widget;
},
addArray: function(newWidgets) {
// note that `each` is only available in newer browsers,
// just loop over the array
for(var i = newWidgets.length; i--; ) {
this.add(newWidgets[i]);
}
},
remove: function(widgetId) {
if (widgetId in this.displayedWidgets) {
delete this.displayedWidgets[widgetId];
}
}
};

Categories

Resources