How to make json tree through group by json data? - javascript

Please take a look at my current json.
[
{"mode": "AR","fname": "ta","lname":"da","w_lng":"2.xx","w_lat":"1.xx"....},
{"mode": "AR","fname": "ta","lname":"da","w_lng":"3.xx","w_lat": "4.xx"....},
{"mode": "AR","fname": "ka","lname":"ja","w_lng":"6.xx","w_lat": "5.xx"....}
]
Now What I am looking for:
{
"mode": "AR",
"results": [
{
"fname": "ta",
"lname": "da",
"w_level": [
{ "w_lng": "2.xx",
"w_lat": "1.xx"
"anothelevel":[........]
},
{"w_lng": "3.xx",
"w_lat": "4.xx"
"anothelevel":[........]
}
]
}
{
"fname": "ka",
"lname": "ja",
"w_level": [
{
"w_lng": "x.xx",
"w_lat": "x.xx"
.....................
}
]
}
]
}
It is same as we do in SQL group by. suppose First group by world, then country, then city, then village etc. I was tried through group by. but the result is not my expected output. Please suggest me what should I do.

objMap = {};
for (let temp of obj) {
if (!objMap[temp.mode]) {
objMap[temp.mode] = { mode: temp.mode, results: [] }
}
let tempObj = { w_level: [], fname: temp.fname, lname: temp.lname };
let w_level = {};
for (let key of Object.keys(temp)) {
if (key !== "fname" && key !== 'lname' && key !== 'mode') {
w_level[key] = temp[key];
}
}
tempObj.w_level.push(w_level)
objMap[temp.mode].results.push(tempObj)
}
NOTE:get object by using Object.values(objMap);

Solution using reduce:
const inArr = [{"mode":"AR","fname":"Kiran","lname":"Dash","w_lng": "1.23", "w_lat": "2.23"},{"mode":"AR1","fname":"Suman","lname":"Dash","w_lng": "3.23", "w_lat": "4.23"},{"mode":"AR","fname":"Raman","lname":"Dash","w_lng": "5.23", "w_lat": "6.23"},{"mode":"AR","fname":"Milan","lname":"Dash","w_lng": "7.23", "w_lat": "8.23"},{"mode":"AR1","fname":"Naman","lname":"Dash","w_lng": "8.23", "w_lat": "9.23"},{"mode":"AR2","fname":"Phulan","lname":"Dash","w_lng": "10.23", "w_lat": "11.23"}]
console.log(
Object.values(inArr.reduce((item, currItem) => {
var { mode, fname, lname } = currItem;
if (!item[mode]) item[mode] = { mode, results: [] };
let w_level = {};
for (let key of Object.keys(currItem)) {
if (key !== "fname" && key !== 'lname' && key !== 'mode') {
w_level[key] = currItem[key];
}
}
item[mode].results.push({fname: fname, lname: lname, w_level: [w_level]});
return item;
}, {}))
);
Code walk through:
Loop over the input array, and group into an object indexed by mode.
Create an object with a result array if the mode doesn't exist yet, and push to that array.
Note: For the sake of simplicity, I have done it to one level. Please use the same approach to create multiple levels if you want.

------At last I found solution-----------
const reduceArrayByKeys = (inArr, keys, restKey) => {
const reduced = inArr.reduce((prev, cur) => {
const copied = { ...cur }
keys.forEach(key => delete copied[key])
const existing = prev.find(item => keys.every(key => item[key] === cur[key]))
if (existing) {
existing[restKey].push(copied)
} else {
const newItem = {}
keys.forEach(key => newItem[key] = cur[key])
newItem[restKey] = [copied]
prev.push(newItem)
}
return prev
}, [])
return reduced
}
const reduced = reduceArrayByKeys(inArr, ['mode'], 'results')
reduced.forEach(item => {
const results = item.results
item.results = reduceArrayByKeys(results, ['fname', 'lname'], 'w_level')
item.results.forEach(child => {
child.w_level = reduceArrayByKeys(child.w_level, ['w_lng', 'w_lat'],
'other')
})
})

Related

Convert array of objects to an object

I have created this function, however is not quite right. I get this response from it:
[
{
manufacturer: [
'AUDI'
]
},
{
body_colour: {
'BLACK'
}
}
]
However what I want is:
{
manufacturer: [
'AUDI'
],
body_colour: {
'BLACK'
}
}
How can I get to this? This is what I have at the moment:
checkForQueryString() {
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
let searchParams = Object.entries(params).map(([key, value]) => {
return {
[key]: value.split(',')
}
});
return searchParams;
},
Query String: ?manufacturer=AUDI&body_colour=BLACK
Use reduce not map
const params = {
manufacturer: "AUDI",
body_colour: "BLACK"
}
let searchParams = Object.entries(params).reduce((acc, [key, value]) => {
return {
...acc,
[key]: value.split(',')
}
}, {});
console.log(searchParams)
Object.fromEntries(urlSearchParams.entries()), Object.entries(params) are not necessary.
You can use a simple forEach function to achieve the desired result as from MDN DOCS.
function checkForQueryString() {
const searchParams = new URLSearchParams(window.location.search);
var result = {};
searchParams.forEach(function(value, key) {
result[key] = value.split(',');
});
return result;
}
console.log( checkForQueryString() );
When url is http:example.com?manufacturer=audi,tesla&body_colour=black,white
the output would be
{
"manufacturer": [
"audi",
"tesla"
],
"body_colour": [
"black",
"white"
]
}
Assumin you meant by your input:
body_colour: [
'BLACK'
]
The answer can be:
let myArray = [
{
manufacturer: ['AUDI']
},
{
body_colour: ['BLACK']
}
];
let newObj = Object.assign({}, ...myArray)
You can make use of Object.fromEntries with split and map:
const str = 'manufacturer=AUDI&body_colour=BLACK';
console.log(Object.fromEntries(str.split('&').map(o=>[o.split('=')[0],[o.split('=')[1]]])));

Make a short version of JSON by merging the key value pairs

I have a json
input_lookup = [{"keyprefixname": "fruit","resultkey":"sweet" },
{"keyprefixname": "rate","resultkey":"ratex" }]
input = {
'fruit_a': "red apple"
'fruit_b': "green apple"
'rate_a': "10$"
'rate_b': "20$"
'vegetable_a': "spinach"
'vegetable_b': "carrot"
}
The input json has some prefixes listed in lookup and we need to merge the listed ones forming a new combined value json key pairs
the expected output is
result_output = {
'sweet': "red apple,green apple"
'ratex': "10$,20$"
'vegetable_a': "spinach" // not to combine this since it wont exist in lookup
'vegetable_b': "carrot"
}
I have tried with
result_output = {}
for(key in input_lookup){
if(key.indexOf(input_lookup) > -1)
key = key+ input_lookup[key]
}
There are several ways to do this. Here's a reducer, using Array.find to compare the lookup values to a value from the input:
const lookup = [
{prefix: "fruit", key: "sweet" },
{prefix: "rate", key: "ratex" },
];
const input = {
fruit_a: "red apple",
fruit_b: "green apple",
rate_a: "10$",
rate_b: "20$",
vegetable_a: "spinach",
vegetable_b: "carrot",
};
const reducedWithArrayOfValues = Object.entries(input)
.reduce( (acc, [key, value]) => {
const nwKey = lookup.find(v => key.startsWith(v.prefix));
return nwKey
? { ...acc, [nwKey.key]: (acc[nwKey.key] ||[]).concat(value) }
: { ...acc, [key]: value };
}, {}
);
const reducedWithStringValues = Object.entries(input)
.reduce( (acc, [key, value]) => {
const nwKey = lookup.find(v => key.startsWith(v.prefix));
return nwKey
? { ...acc, [nwKey.key]: `${acc[nwKey.key] ? `${
acc[nwKey.key]}#` : ""}${value}` }
: { ...acc, [key]: value };
}, {}
);
document.querySelector(`pre`).textContent =
JSON.stringify(reducedWithStringValues, null, 2);
document.querySelector(`pre`).textContent += `\n---\n${
JSON.stringify(reducedWithArrayOfValues, null, 2)}`;
<pre></pre>
here you go
function getAggregateKey(key, value) {
const result = input_lookup.find((item) => key.includes(item.keyprefixname));
if (result) {
return result["resultkey"];
}
return key;
}
const arrayObject = Object.entries(input).reduce((acc, cur) => {
const aggKey = getAggregateKey(cur[0]);
if (!(aggKey in acc)) {
acc[aggKey] = [];
}
acc[aggKey].push(cur[1])
return acc;
}, {});
const result = Object.entries(arrayObject).reduce((acc, cur) => {
acc[cur[0]] = cur[1].join(',');
return acc;
}, {});
console.log(result);
let input_lookup = [{
"keyprefixname": "fruit",
"resultkey": "sweet"
}, {
"keyprefixname": "rate",
"resultkey": "ratex"
}];
let input = {
'fruit_a': "red apple",
'fruit_b': "green apple",
'rate_a': "10$",
'rate_b': "20$",
'vegetable_a': "spinach",
'vegetable_b': "carrot"
};
// first we need a good lookup object the default is an array
// we made fruit > sweet and rate > ratex
// this is help later in the code
var good_lookup = {};
for(let i = 0; i < input_lookup.length ; i++){
let good_key = input_lookup[i]['keyprefixname'];
let good_val = input_lookup[i]['resultkey'];
good_lookup[good_key] = good_val;
}
let result_output = {};
for(let key in input ){
let to_lookup = key.split('_');
let to_lookup_key = to_lookup[0];//fruit, rate
var to_aggregate = good_lookup[to_lookup_key];
if(to_aggregate){
if(result_output[to_aggregate]){
result_output[to_aggregate] = result_output[to_aggregate] + ", " + input[key];
} else {
result_output[to_aggregate] = input[key];
}
} else {
result_output[key] = input[key];
}
}
console.log(result_output);
here is a fiddle for the code https://jsfiddle.net/z8usmgja/1/

spread operator to copy values to nested object dynamically using array forEach loop

This is the code I made, its actually from the react project I am working on, where I wanted to add more key-value pairs under particular keys. So I made a similar sample code to know how to do it, but unfortunately, I can't find a solution on the internet.
Please help
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
]
let savedFilter = "";
const savefilter = () => {
const saveName = "fooCriteria";
filteredSearchItems.forEach(item => {
if (!savedFilter) {
savedFilter={ [saveName]: { [item.id]: item.value } };
} else
savedFilter={...savedFilter.saveName,...{
...savedFilter.saveName,
...{ [item.id]: item.value }
}};
});
};
savefilter();
console.log("savedFilter :",savedFilter)
output
savedFilter : { das5: 46 }
My Expected output that I wanted
{ fooCriteria: { das: 45, das3: 48, das4: 47, das5: 46 } }
PS: I wanted to give fooCriteria as savename variable there is a reason. since the name of the object is determined by the user
const saveName = document.getElementById("seachSaveInput").value;
const filteredSearchItems=[{"id":"das","value":45},{"id":"das3","value":48},{"id":"das4","value":47},{"id":"das5","value":46}];
let fooCriteria = filteredSearchItems.reduce((acc,{id,value})=>(acc[id]=value,acc),{});
console.log({fooCriteria})
You can use reduce method
instead of forEach reduce makes more sense.
const filteredSearchItems = [
{
'id': 'das',
'value': 45
},
{
'id': 'das3',
'value': 48
},
{
'id': 'das4',
'value': 47
},
{
'id': 'das5',
'value': 46
}
];
const savedFilter = {};
const saveFilter = () => {
const saveName = 'fooCriteria';
savedFilter[saveName] = filteredSearchItems.reduce((saved, item) => {
saved[item.id] = item.value;
return saved;
}, savedFilter[saveName] || {});
};
saveFilter();
console.log('savedFilter :', savedFilter);
I'd do a shallow copy with spread notation:
// If you want to add to the [saveName] entry if it exists:
savedFilter = {...savedFilter, [saveName]: savedFilter ? {...savedFilter[saveName]} : {}};
// If you want to *replace* the [saveName] entry, not add to it:
savedFilter = {...savedFilter, [saveName]: {}};
then update the result with a loop:
for (const {id, value} of filteredSearchItems) {
savedFilter[saveName][id] = value;
}
Here's an example assuming you want to replace the [saveName] property if it exists:
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
];
let savedFilter = {somethingAlreadyThere: 42};
const saveName = "fooCriteria";
savedFilter = {...savedFilter, [saveName]: {}};
for (const {id, value} of filteredSearchItems) {
savedFilter[saveName][id] = value;
}
console.log(savedFilter);
There are other, more complicated ways (reduce, map and Object.fromEntries, ...), but they don't have any advantage over the simple, straightfoward loop.
That said, the map and Object.fromEntries version is really concise, if that's your thing:
// Assumes you want to replace the [saveName] property entirely
const saveName = "fooCriteria";
savedFilter = {
...savedFilter,
[saveName]: Object.fromEntries(filteredSearchItems.map(({id, value}) => [id, value]))
};
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
];
let savedFilter = {somethingAlreadyThere: 42};
const saveName = "fooCriteria";
savedFilter = {
...savedFilter,
[saveName]: Object.fromEntries(filteredSearchItems.map(({id, value}) => [id, value]))
};
console.log(savedFilter);
Don't be fooled, though, there's a loop in there (actually two of them, one for map, the other for fromEntries). :-)
Using ...spread operator you can do it something like this:
const filteredSearchItems = [{
"id": "das",
"value": 45
},
{
"id": "das3",
"value": 48
},
{
"id": "das4",
"value": 47
},
{
"id": "das5",
"value": 46
},
]
let savedFilter = "";
const savefilter = () => {
const saveName = "fooCriteria";
let res = {};
filteredSearchItems.forEach(item => {
if (!savedFilter) {
savedFilter = { [saveName]: { [item.id]: item.value } };
} else
savedFilter[saveName] = {
...{ [item.id]: item.value }, ...savedFilter[saveName]
}
});
};
savefilter();
console.log("savedFilter :", savedFilter.fooCriteria)
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
]
var a1={};
for(let i=0 ; i<filteredSearchItems.length;i++){
let id1 = filteredSearchItems[i].id;
let id2 = filteredSearchItems[i].value;
a1[id1] = id2;
}
var t2 = {"fooCriteria": a1}
console.log(JSON.stringify(t2));
Output : {"njkcnv":{"das":45,"das3":48,"das4":47,"das5":46}}

Group like JSON objects into arrays

I have a model returned by a library in the following format:
var givenData = [{"fName": "john"}, {"fName": "mike"}, {"country": "USA"}]
How do I group the "fName" together and add '[]' to get:
{ 'fName[]': ['john','mike'],'country[]': ['USA'] };
**Note country and fName are not related at all.
Suggestion (using ES6 syntax)
const transformData = (data) => {
const newData = {}
data.forEach( (item) => {
for (let key in item) {
const newKey = key + "[]"
if (!newData.hasOwnProperty(newKey)) newData[newKey] = []
newData[newKey].push(item[key])
}
})
return newData
}
/* added some extra keys just to test */
let givenData = [
{"fName": "john", "country": "England"},
{"fName": "mike"},
{"country": "USA"},
{"language": "English"}
]
console.log(transformData(givenData))
/*
{
"fName[]": ["john","mike"],
"country[]": ["England","USA"],
"language[]":["English"]
}
*/
You can iterate over the array and push the date to the desired field.
var givenData = [{"fName": "john"}, {"fName": "mike"}, {"country": "USA"}]
var result = {
'fName[]': [],
'country[]': []
};
givenData.forEach(function (data) {
if (data.fName) {
result['fName[]'].push(data.fName);
}
if (data.country) {
result['country[]'].push(data.country);
}
});
console.log(result);
You could take the key and build an object with the key and arrays as properties.
var givenData = [{"fName": "john"}, {"fName": "mike"}, {"country": "USA"}],
grouped = givenData.reduce(function (r, o) {
var key = Object.keys(o)[0] + '[]';
r[key] = r[key] || [];
r[key].push(o[Object.keys(o)[0]]);
return r;
}, Object.create(null));
console.log(grouped);
In ES6:
const newData = givenData.reduce(function (r, o) {
const key = `${Object.keys(o)[0]}[]`;
return { ...r, [key]: [ ...r[key], o[key] ] }
}, {});
This doesn't modify your original data and is very clean.

How to get all key in JSON object (javascript)

{"document":
{"people":[
{"name":["Harry Potter"],"age":["18"],"gender":["Male"]},
{"name":["hermione granger"],"age":["18"],"gender":["Female"]},
]}
}
From this JSON example, I would like to get the keys such as name, age, gender for each people.
How to do this?
I use Object.keys which is built into JavaScript Object, it will return an array of keys from given object MDN Reference
var obj = {name: "Jeeva", age: "22", gender: "Male"}
console.log(Object.keys(obj))
Try this
var s = {name: "raul", age: "22", gender: "Male"}
var keys = [];
for(var k in s) keys.push(k);
Here keys array will return your keys ["name", "age", "gender"]
var input = {"document":
{"people":[
{"name":["Harry Potter"],"age":["18"],"gender":["Male"]},
{"name":["hermione granger"],"age":["18"],"gender":["Female"]},
]}
}
var keys = [];
for(var i = 0;i<input.document.people.length;i++)
{
Object.keys(input.document.people[i]).forEach(function(key){
if(keys.indexOf(key) == -1)
{
keys.push(key);
}
});
}
console.log(keys);
ES6 of the day here;
const json_getAllKeys = data => (
data.reduce((keys, obj) => (
keys.concat(Object.keys(obj).filter(key => (
keys.indexOf(key) === -1))
)
), [])
)
And yes it can be written in very long one line;
const json_getAllKeys = data => data.reduce((keys, obj) => keys.concat(Object.keys(obj).filter(key => keys.indexOf(key) === -1)), [])
EDIT: Returns all first order keys if the input is of type array of objects
var jsonData = { Name: "Ricardo Vasquez", age: "46", Email: "Rickysoft#gmail.com" };
for (x in jsonData) {
console.log(x +" => "+ jsonData[x]);
alert(x +" => "+ jsonData[x]);
}
This function should return an array of ALL the keys (i.e. the key names) in a JSON object including nested key/value pairs.
function get_all_json_keys(json_object, ret_array = []) {
for (json_key in json_object) {
if (typeof(json_object[json_key]) === 'object' && !Array.isArray(json_object[json_key])) {
ret_array.push(json_key);
get_all_json_keys(json_object[json_key], ret_array);
} else if (Array.isArray(json_object[json_key])) {
ret_array.push(json_key);
first_element = json_object[json_key][0];
if (typeof(first_element) === 'object') {
get_all_json_keys(first_element, ret_array);
}
} else {
ret_array.push(json_key);
}
}
return ret_array
}
Using this function on the OP's original object
const op_object =
{
"document":{
"people":[
{
"name":[
"Harry Potter"
],
"age":[
"18"
],
"gender":[
"Male"
]
},
{
"name":[
"hermione granger"
],
"age":[
"18"
],
"gender":[
"Female"
]
}
]
}
}
var all_keys = [];
function get_all_json_keys(json_object, ret_array = []) {
for (json_key in json_object) {
if (typeof(json_object[json_key]) === 'object' && !Array.isArray(json_object[json_key])) {
ret_array.push(json_key);
get_all_json_keys(json_object[json_key], ret_array);
} else if (Array.isArray(json_object[json_key])) {
ret_array.push(json_key);
first_element = json_object[json_key][0];
if (typeof(first_element) === 'object') {
get_all_json_keys(first_element, ret_array);
}
} else {
ret_array.push(json_key);
}
}
return ret_array
}
get_all_json_keys(op_object, all_keys);
console.log(all_keys);
should yield
[ 'document', 'people', 'name', 'age', 'gender' ]
Note: This will return a unique list of all key names.
We must "parse" our jsonObject
console.log('{"key0":"value0", "key1":"value1"}');
var jsonObject = JSON.parse('{"key0":"value0", "key1":"value1"}')
Object.keys(jsonObject).forEach(key => {
console.log(jsonObject[key]); //values
console.log(key); //keys
})

Categories

Resources