I have a JSON object array where I need to rename the keys based on values in the first object. Trying to do this in NodeJS but not having any luck.
I could probably brute force it with a couple of loops but was hoping for a more scalable solution since the number of "columns" change from time to time.
Here is an example
[{"A" : "Key1", "B" : "Key2", "C" : "Key3"},
{"A" : "Data1", "B" : "Data2", "C" : "Data3"},
{"A" : "Data5", "B" : "Data5", "C" : "Data7"}]
I would like the result to be like
[{"Key1" : "Key1", "Key1" : "Key2", "Key1" : "Key3"},
{"Key1" : "Data1", "Key2" : "Data2", "Key3" : "Data3"},
{"Key1" : "Data5", "Key2" : "Data5", "Key3" : "Data7"}]
let arr = [{"A" : "Key1", "B" : "Key2", "C" : "Key3"},
{"A" : "Data1", "B" : "Data2", "C" : "Data3"},
{"A" : "Data5", "B" : "Data5", "C" : "Data7"}];
const keys = Object.keys(arr[0]).map(i => arr[0][i]);
let result = arr.map(obj => {
const replacedObj = {};
const oriKeys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
replacedObj[keys[i]] = obj[oriKeys[i]]
};
return replacedObj;
});
console.log(JSON.stringify(result));
Using Object.entries() with some creative mapping, reducing, destructuring and spreading:
o = i.map(x => Object.entries(x).reduce((a, [k, v]) => ({...a, [i[0][k]]: v}), {}));
Complete snippet:
let input, output;
input = [
{"A" : "Key1", "B" : "Key2", "C" : "Key3"},
{"A" : "Data1", "B" : "Data2", "C" : "Data3"},
{"A" : "Data5", "B" : "Data5", "C" : "Data7"}
];
output = input.map(x => Object.entries(x).reduce((a, [k, v]) => ({...a, [input[0][k]]: v}), {}));
console.log(output);
Lets say the old array is stored in a var called oldArray:
var keys = Object.keys(oldArray[0]); // get first object keys
var newArray = oldArray.map(function(obj,index){
// Iterate over each object to replace keys
if(index === 0) return obj; /* if first object we dont need to replace
keys */
var objKeys = Object.keys(obj); //old keys for reference only
return Object assign({},{
[keys[0]]: obj[objKeys[0], // assigning first object keys with
current
[keys[1]]: obj[objKeys[1], // object values
[keys[2]]: obj[objKeys[3],
});
});
console.log(newArray);
/* You also can change the key value asignation with a for, so you
can handle not only 3 key values object, this could be optimized
with es6 ans spread operator definition but rather to implement it in
es5 for less complexity */
Related
i have an object
{
"name" : "foo",
"tag_name" : "grocery",
"tag_id" : "id",
"tag_nested_id" : "123",
}
I want the output as
{
"name" : "foo",
"tag" : {
"name" : "grocery",
"id" : "id",
"nested" : {
"id" : "123"
}
}
}
Is there any easy way to achieve this using lodash/underscore?
No external libraries required, vanilla JS split on _ and .reduce
const data = {
"name" : "foo",
"tag_name" : "grocery",
"tag_id" : "id",
"tag_nested_id" : "123"
};
const result = Object.entries(data).reduce((object, [key, val]) => {
const splitKey = key.split('_');
const last = splitKey.pop();
splitKey.reduce((obj, x) => obj[x] ??= {}, object)[last] = val;
return object;
}, {})
console.log(JSON.stringify(result, null, 2));
The answer by mani is as good as it gets, but with Underscore, we can create a version that is backwards compatible with older environments:
var data = {
"name" : "foo",
"tag_name" : "grocery",
"tag_id" : "id",
"tag_nested_id" : "123"
};
var result = _.reduce(data, function(object, val, key) {
var splitKey = key.split('_');
var last = splitKey.pop();
_.reduce(splitKey, function(obj, part) {
return obj[part] = obj[part] || {};
}, object)[last] = val;
return object;
}, {})
console.log(JSON.stringify(result, null, 2));
<script src="https://cdn.jsdelivr.net/npm/underscore#1.13.4/underscore-umd-min.js"></script>
There are three types of JSON I can face randomly,
Fist type, object:
{ "a" : "b", "#type" : "Product" }
Second type, array:
[{ "a" : "b", "#type" : "Test" }, { "a" : "b", "#type" : "Product" }]
Third type, nested object:
{ "d" : "e", "f" : { "a" : "b", "#type" : "Product" } }
I'm trying to get the the object, which contains "#type" : "Product", so my desired result would be[{ "a" : "b", "#type" : "Product" }] for all of types.
To get this result, in case of second one, I can use obj.filter(d => d["#type"]=="Product") and for the first one, made an empty array, var empty_array = []; empty_array.push(obj) and then used that same filter as a second one.
However, I don't know the way to get the desired result when the properties are in nested object.
Is there any JSON filter to get a desired result for all of types?
When I used JsonPath, I used $..[?(#["\x40type"] =="Product" for deep search in Json, and it works pretty well, however I would like to find the way in Javascript itself.
Many thanks in advance :)
Can you try the below approach
// This method will return the type of object. In case of array or JSON, it will return array or json instead of object.
function getType(obj) {
if (typeof obj === 'object') {
if (Array.isArray(obj)) {
return 'array';
}
return 'json';
}
return typeof obj;
}
// This method will return either the required JSON or null.
function getObject(obj) {
// Check the type if it is JSON.
if (getType(obj) === 'json') {
// If the current object has a key named #type, return the object.
if (Object.keys(obj).includes('#type') && obj['#type'] === 'Product') return obj;
// Otherise call the method recursively for each value of JSON.
const values = Object.values(obj);
for (let i = 0, n = values.length; i < n; ++i) {
const returnVal = getObject(values[i]);
// If the value is required JSON, return that value.
if (returnVal) return returnVal;
}
// Check if the type of object is array.
} else if (getType(obj) === 'array') {
// Call the function recursively for each value of the array.
for (let i = 0, n = obj.length; i < n; ++i) {
const returnVal = getObject(obj[i]);
// If you get the required JSON, return it.
if (returnVal) return returnVal;
}
}
// If you didn't get the required JSON, return null.
return null;
}
var a = { "a" : "b", "#type" : "Product" };
var b = [{ "a" : "b", "#type" : "Test" }, { "a" : "b", "#type" : "Product" }];
var c = { "d" : "e", "f" : { "a" : "b", "#type" : "Product" } };
console.log(getObject(a));
console.log(getObject(b));
console.log(getObject(c));
Here is a concise solution using object-scan:
// const objectScan = require('object-scan');
const d1 = { a: 'b', '#type': 'Product' };
const d2 = [{ a: 'b', '#type': 'Test' }, { a: 'b', '#type': 'Product' }];
const d3 = { d: 'e', f: { a: 'b', '#type': 'Product' } };
const find = (data) => objectScan(['**.#type'], {
abort: true,
rtn: 'parent',
filterFn: ({ value }) => value === 'Product'
})(data);
console.log(find(d1));
// => { a: 'b', '#type': 'Product' }
console.log(find(d2));
// => { a: 'b', '#type': 'Product' }
console.log(find(d3));
// => { a: 'b', '#type': 'Product' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.7.1"></script>
Disclaimer: I'm the author of object-scan
I want to fetch the nested key and manipulates their data.
I have tried 2 methods:
Example 1:
for (let key in the dictionary) {
for (let keys in dictionary[key]) {
console.log(keys)
}
}
Example 2:
for (let key in dictionary) {
for (let k in lng.dictionary[key]["data"]) {
console.log(k)
}
}
In Example 1, I am getting both the keys name and data.
In Example 2,I am getting only a, b, c, d, yes, no, f, hgs, cft, vit. not
their values.
But I want to:
Fetch only data.
and manipulate their values like {"key":"a","value":"some text"},{"key":"b","value":"some text"},{"key":"c","value":"c for"},{},{}.
here is my Json object
"dictionary" : {
"bar" : {
"name" : "Bar",
"data" : {
"a" : "some text",
"b" : "some text",
"c" : "c for",
"d" : "some text",
"yes" : "true",
"No" : "true",
"f" : "some text"
}
},
"text" : {
"name" : "Text",
"data" : {
"hgs" : "some text",
"cft" : "some text",
"vit" : "some text"
}
}
}
You can use Object.values to extract the inner data object and for each key and value of the data object which can be iterated by Object.entries we would form a temp object.
Using Array.reduce we can accumulate the temp objects into an array.
const data = {"dictionary":{"bar":{"name":"Bar","data":{"a":"some text","b":"some text","c":"c for","d":"some text","yes":"true","No":"true","f":"some text"}},"text":{"name":"Text","data":{"hgs":"some text","cft":"some text","vit":"some text"}}}};
const dataProcessed = Object.values(data.dictionary).reduce((acc, obj) => {
Object.entries(obj.data).forEach(([key, value])=>{
temp = {};
temp["key"] = key;
temp["value"] = value;
acc.push(temp);
});
return acc;
}, []);
console.log(dataProcessed);
I have seen lots of answers in the other way,
but i couldnt find array of objects into object of objects
the following example of what I want:
i want to transform this:
var = [
{"a" : {"min" : 0.5}},
{"b" : {"max" : 0.6}},
{"c" : {"min" : 0.3}}]
to this:
var = {
"a" : {"min" : 0.5},
"b" : {"max" : 0.6},
"c" : {"min" : 0.3}
}
array of objets to object of objects,
So I can use this solver: https://github.com/JWally/jsLPSolver
thanks
You can do this using Object.assign() and ES6 spread syntax.
var arr = [{"a" : {"min" : 0.5}}, {"b" : {"max" : 0.6}}, {"c" : {"min" : 0.3}}]
var result = Object.assign({}, ...arr);
console.log(result)
const obj = arr.reduce((result, item) => {
const key = Object.keys(item)[0];
result[key] = item[key];
return result;
}, {});
Array.prototype.reduce() and Object.keys() are your friends in here.
I think it is kind of difficult to generalize this and make it more generic, since you have to know which key of the item should be used as key of the result. But in this case, there is only one, so easy to use.
I suppose you should create class or struct of objects.
You can do like this. First loop over the array and just add the key & value from each object to the new object
var firstArray = [{
"a": {
"min": 0.5
}
},
{
"b": {
"max": 0.6
}
},
{
"c": {
"min": 0.3
}
}
]
var arrayKey = {};
firstArray.forEach(function(item) {
for (var keys in item) {
arrayKey[keys] = item[keys]
}
})
console.log(arrayKey)
I have an object which has json objects called
mainobject =
Array[2]
>0: object
>Innerobject1 : Array[2]
>0 : object
Name : "Xavier"
Dup : "B"
>1 : object
Name : "Gh"
Dup : "B"
>1: object
>Innerobject2 : Array[2]
>0 : object
Name : "Cat"
Dup : "C"
>1 : object
Name : "Dog"
Dup : "D"
I need to make the "dup" as "" which was already present in the first object if any .My expected output is:
Array[2]
>0: object
>Innerobject1 : Array[2]
>0 : object
Name : "Xavier"
Dup : "B"
>1 : object
Name : "Gh"
Dup : ""
>1: object
>Innerobject2 : Array[2]
>0 : object
Name : "Cat"
Dup : "C"
>1 : object
Name : "Dog"
Dup : "D"
Edit:
The object in json format:
:
"[{"Innerobject1":[{"Name" :"Xavier","Dup":"B"},{"Name" :"Gh","Dup":"B"}]},
{"Innerobject2":[{"Name" : "Cat","Dup":"C"},{"Name":"Dog", "Dup":"D"}]}]"
I'm not quite sure that I have interpreted your posted array of objects correct. But you can do something like this:
Iterate over the array and store the key you want to be unique in an object. When encountered more then once set the new value to an empty string:
var seen = {};
mainobject.forEach(function(obj) {
if (seen[obj.Name]) {
obj.Name = "";
}
seen[obj.Name] = true;
});
You might need multiply iterations, dependents on how many nested arrays you got:
var seen = {};
mainobject.forEach(function(inner_arr) {
inner_arr.forEach(function(obj) {
if (seen[obj.Name]) {
obj.Name = "";
}
seen[obj.Name] = true;
});
});
The solution using Array.forEach and Object.keys functions:
var mainobject = JSON.parse('[{"Innerobject1":[{"Name" :"Xavier","Dup":"B"},{"Name" :"Gh","Dup":"B"}]},{"Innerobject2":[{"Name" : "Cat","Dup":"C"},{"Name":"Dog", "Dup":"D"}]}]');
mainobject.forEach(function(obj){
Object.keys(obj).forEach(function(k){
obj[k].forEach(function(o){
if (this["Dup"]) {
(this["Dup"].indexOf(o["Dup"]) !== -1)? o["Dup"] = "" : this["Dup"].push(o["Dup"]);
} else {
this["Dup"] = [o["Dup"]];
}
})
});
}, {});
console.log(JSON.stringify(mainobject, 0, 4));
The console.log output:
[
{
"Innerobject1": [
{
"Name": "Xavier",
"Dup": "B"
},
{
"Name": "Gh",
"Dup": ""
}
]
},
{
"Innerobject2": [
{
"Name": "Cat",
"Dup": "C"
},
{
"Name": "Dog",
"Dup": "D"
}
]
}
]