JSON data formatting through dynamic Key, Value - javascript

I have a JSON response data. I want to display it as a tabular format but I am not able to do it correctly. please correct me where I am doing wrong.
Response Data
const response = [
{
"key": "Name",
"data": [ "Tom", "Mark", "Jack" ]
},
{
"key": "OfcLocation",
"data": [ "USA", "Spain", "Japan" ]
},
{
"key": "IPAddress",
"data": [ "XX.XXX.X.XX", "XX.XXX.X.XX", "XX.XXX.X.XX" ]
},
{
"key": "Port",
"data": [ "4300", "4080", "9200" ]
},
{
"key": "Role",
"data": [ "Admin", "Limited", "Admin" ]
}
];
Desired Output Format
[
{ "Name": "Tom", "OfcLocation": "USA", "IPAddress": "XX.XXX.X.XX", "Port": "4300", "Role": "Admin" },
{ "Name": "Mark", "OfcLocation": "Spain", "IPAddress": "XX.XXX.X.XX", "Port": "4080", "Role": "Limited" },
{ "Name": "Jack", "OfcLocation": "Japan", "IPAddress": "XX.XXX.X.XX", "Port": "9200", "Role": "Admin" }
]
Code
let formatedData = [];
let rowArr = {};
for( let i=0; i< response.length; i++) {
for( let j=0;j< response[i].data.length; j++) {
rowArr[response[i].key] = response[i].data[j];
}
formatedData.push(rowArr);
}

You can get the result you want using Array.reduce function.
const response = [
{
"key": "Name",
"data": [ "Tom", "Mark", "Jack" ]
},
{
"key": "OfcLocation",
"data": [ "USA", "Spain", "Japan" ]
},
{
"key": "IPAddress",
"data": [ "XX.XXX.X.XX", "XX.XXX.X.XX", "XX.XXX.X.XX" ]
},
{
"key": "Port",
"data": [ "4300", "4080", "9200" ]
},
{
"key": "Role",
"data": [ "Admin", "Limited", "Admin" ]
}
];
const result = response.reduce((acc, cur) => {
cur.data.forEach((item, index) => {
if (acc.length <= index) {
acc.push({
[cur.key]: item
});
} else {
acc[index][cur.key] = item;
}
});
return acc;
}, []);
console.log(result);

You need to switch the inner and outer loop and put let rowArr = {}; inside the outer loop
let formatedData = [];
let rowArr = {};
for (let j = 0; j < response[0].data.length; j++) {
let rowArr = {};
for (let i = 0; i < response.length; i++) {
rowArr[response[i].key] = response[i].data[j];
}
formatedData.push(rowArr);
}

Make an array of empty objects and put the data in them...
let sortedArray = [];
for(let i=0 ; i< response[0].data.length ; i++){
sortedArray.push(new Object);
}
function sort() {
response.forEach((el) => {
el.data.forEach((elem, i) => {
sortedArray[i][el.key] = elem;
});
});
}
sort();
console.log(sortedArray);

Related

map values to an array inside an object

I have this object below
{
"root": {
"data": {
"page": 1,
"contents": [
{
"node": {
"id": "UzpfSTE",
"stats": {
"viewers": {
"nodes": [
{
"id": "1",
"name": "John"
},
{
"id": "2",
"name": "Shaun"
}
]
}
}
}
},
{
"node": {
"id": "UzpfSTG",
"stats": {
"viewers": {
"nodes": [
{
"id": "3",
"name": "Liam"
}
]
}
}
}
}
]
}
}
}
There is contents node, each of them will have many viewers, all I want is to extract all viewers name to an array, in this instance my result will be [John, Shaun, Liam]
I have this approach:
const data = JSON.parse(rt)
const contents = data.root.data.contents
const newArray = []
for (i = 0; i < contents.length; i++) {
arr2 = contents[i].node.stats.viewers.nodes
for (n = 0; n < arr2.length; n++) {
name = arr2[n].name
newArray.push(name)
}
}
console.log(newArray)
>>> [John, Shaun, Liam]
Which does the job, but occasionaly the object key names change and I have to alter everytime.
So is there more elegant way to do this?
You can simplify that imperative logic like this.
I don't understand what you mean by "the object key names change" though
const data = {
"root": {
"data": {
"page": 1,
"contents": [{
"node": {
"id": "UzpfSTE",
"stats": {
"viewers": {
"nodes": [{
"id": "1",
"name": "John"
},
{
"id": "2",
"name": "Shaun"
}
]
}
}
}
},
{
"node": {
"id": "UzpfSTG",
"stats": {
"viewers": {
"nodes": [{
"id": "3",
"name": "Liam"
}]
}
}
}
}
]
}
}
}
const names = data.root.data.contents.flatMap(({
node: {
stats: {
viewers: {
nodes
}
}
}
}) => nodes.map(({
name
}) => name))
console.log(names)
const data = JSON.parse(rt)
const contents = data.root.data.contents
const viewers = contents.map(item => item.node.stats.viewers.nodes).flat()
const viewerNames = viewers.map(viewer => viewer.name)

Javascript Recursion thru children and display in HTML

I want to display a result based on nested children's value. I am using the recursion function for this. I am having trouble with how will I display it to HTML based on the example result below.
I am using React.js.
For now I am using console.log.
Here is my code: (Sample data are in the bottom)
function recursion(data, label) {
if (!data) {
return;
}
for (let a = 0; a < data.length; a++) {
const item = data[a]
if (!item.items) {
const isLast = data.length - a === a
console.log(`(${item.course_id}) ${ isLast ? '' : label} `)
} else {
if (label) console.log(label)
recursion(item.items, item.type)
}
}
}
/*
Example result that I want to achieve is something like be:
(1894 $or 1501)
$or
(7068 $or 7120 or 7141)
$or
(997 $and 9001)
$or
(7256 $or 4534)
*/
//My sample data:
const data = [{
"type": "$or",
"items": [{
"course_id": "1894"
},
{
"course_id": "1501"
},
{
"type": "$or",
"items": [{
"course_id": "7068"
},
{
"course_id": "7120"
},
{
"course_id": "7141"
},
{
"type": "$and",
"items": [{
"course_id": "997"
},
{
"course_id": "9001"
}
]
}
]
},
{
"type": "$or",
"items": [{
"course_id": "7256"
},
{
"course_id": "4534"
}
]
}
]
}]
//start here
recursion(data)
Puts all leaf nodes (nodes without children) in items into an array, then recurses into nodes. Then joins them all together using the $type.
const data = [{
"type": "$or",
"items": [
{
"course_id": "1894"
},
{
"course_id": "1501"
},
{
"type": "$or",
"items": [
{
"course_id": "7068"
},
{
"course_id": "7120"
},
{
"course_id": "7141"
},
{
"type": "$and",
"items": [
{
"course_id": "997"
},
{
"course_id": "9001"
}
]
}
]
},
{
"type": "$or",
"items": [
{
"course_id": "7256"
},
{
"course_id": "4534"
}
]
}
]
}]
/*
function recursion(data, label) {
if (!data) { return; }
for (let a = 0; a < data.length; a++) {
const item = data[a]
if (!item.items){
console.log(`${item.course_id} ${label} `)
} else {
console.log('')
console.log(label || '')
setParentLabel = item.type
const child = recursion(item.items, setParentLabel)
}
}
}
*/
const recursion = (data, label) => {
let nodes = [[]];
const type = data.type;
data.items.forEach( x => {
const leafs = nodes[0];
const isLeaf = !x.items;
if ( isLeaf ) leafs.push( x.course_id );
else nodes.push( recursion( x, x.type ) );
});
if ( nodes[0].length > 0 )
nodes[0] = '('+nodes[0].join(` ${type} `)+')';
else nodes = nodes.slice(1);
let string = '';
string = nodes.join(`\n${type}\n`);
return string;
};
console.log(recursion({items: data}))
const data = [{
"type": "$or",
"items": [
{
"course_id": "1894"
},
{
"course_id": "1501"
},
{
"type": "$or",
"items": [
{
"course_id": "7068"
},
{
"course_id": "7120"
},
{
"course_id": "7141"
},
{
"type": "$and",
"items": [
{
"course_id": "997"
},
{
"course_id": "9001"
}
]
}
]
},
{
"type": "$or",
"items": [
{
"course_id": "7256"
},
{
"course_id": "4534"
}
]
}
]
}]
/*
Example result that I want to achieve is something like be:
(1894 $or 1501)
$or
(7068 $or 7120 or 7141)
$or
(997 $and 9001)
$or
(7256 $or 4534)
*/
function recursion(data, label) {
if (!data) { return; }
let nodes = [[]];
let leafs = nodes[0];
for (let a = 0; a < data.length; a++) {
const item = data[a]
if (!item.items){
leafs.push(item.course_id)
} else {
setParentLabel = item.type
const child = recursion(item.items, setParentLabel)
nodes.push(child);
}
}
if ( nodes[0].length > 0 )
nodes[0] = '(' + nodes[0].join(` ${label} `) + ')';
else nodes = nodes.slice(1);
return nodes.filter(x=>!!x).join(`\n${label}\n`);
}
console.log(recursion(data))
const unSortedData = [{
"type": "$or",
"items": [{
"course_id": "1894"
},
{
"type": "$or",
"items": [{
"course_id": "7068"
},
{
"course_id": "7120"
},
{
"course_id": "7141"
},
{
"type": "$and",
"items": [{
"course_id": "997"
},
{
"course_id": "9001"
}
]
}
]
},
{
"type": "$or",
"items": [{
"course_id": "7256"
},
{
"course_id": "4534"
}
]
},
{
"course_id": "1501"
}
]
},
{
"type": "$or",
"items": [{
"course_id": "1894"
},
{
"type": "$or",
"items": [{
"course_id": "7068"
},
{
"course_id": "7120"
},
{
"course_id": "7141"
},
{
"type": "$and",
"items": [{
"course_id": "997"
},
{
"course_id": "9001"
}
]
}
]
},
{
"type": "$or",
"items": [{
"course_id": "7256"
},
{
"course_id": "4534"
}
]
},
{
"course_id": "1501"
}
]
}]
/**Inorder to split between two data I have used value.type if you want
*something else then you can use your own delimiter(just replace
*value.type with your requirement). Also if you want to store the looped
*item, you can store it into an array rather than returning string value.
*Example instead of dataJoiner you an use
*const arr = [];
*Inside forEach loop. arr.push(loopItems(value.items, value.type));
*and finally return arr. It's clearly upto you what you want to do with
*the recursed item
**/
function loopData(data) {
let dataJoiner = '';
data.forEach(value => {
dataJoiner = `${dataJoiner}\n ${dataJoiner ? ' ' + value.type + ' ' : dataJoiner}\n ${loopItems(value.items, value.type)})`;
});
console.log(dataJoiner);
return dataJoiner;
};
/** In this method items are sorted as per object type. Objects with only
*course_id are sorted and then Object with items are sorted. After that
*using
*reduce funtion it checks whether item has type and if it hasn't it
*accumulates by joining course_id with the given type. And whenever it
*detects type on the item it recursively calls loopItems whose result is
*accumulated into accumulator i.e. acc
**/
function loopItems(items, type) {
if(items && items.length) {
const sortedItems = items.sort((a, b) => Object.keys(a).length - Object.keys(b).length);
return sortedItems.reduce((acc, item, index) => {
if(item.type) {
return `${acc})\n ${acc ? ' ' + type + ' ' : acc}\n ${loopItems(item.items, item.type)}`;
}
const leftBracket = index === 0 ? '(' : ''
return `${leftBracket }${acc}${acc ? ' ' + type + ' ' : acc}${item.course_id}`;
}, '');
}
}
loopData(unSortedData);
function recursion(items, type = '') {
let result = [];
for (let item of items) {
if (!item.items && !item.type) {
result.push(item.course_id);
} else {
result.push(`(${recursion(item.items, item.type)})`);
}
}
return result.join(` ${type} `);
}
//start here
console.log(recursion(data));

Replace js code with aggregate in mongodb

I have mongo document called groups. This is array of students and subjects.
Each subject has an array of lessons.
Each lesson has an array of marks.
Generally, document looks like this:
[
{
"students": [
{ "_id": "0", "firstName": "Bob", "lastName": "Jhonson" },
{ "_id": "1", "firstName": "Jackie", "lastName": "Chan" }
// other students ...
],
"subjects": [
{
"name": "Algebra",
"lessons": [
{
"date": 1489363200,
"marks": [
{ "student_id": "0", "value": 5 },
{ "student_id": "1", "value": 4 }
// other marks...
]
}, {
"date": 1489622400,
"marks": [
{ "student_id": "0", "value": 3 },
{ "student_id": "1", "value": 2 }
// other marks...
]
}
// other lessons...
]
}
]
}
]
Then I use js function to transform this data to something like this:
[
{
"_id": "5a89ca11abc4ffd25a430420",
"subjects": [
{
"name": "Algebra",
"dates": [1489363200, 1489622400],
"students": [
{
"_id": "0",
"firstName": "Bob",
"lastName": "Jhonson",
"marks": [ 5, 3 ]
},
{
"_id": "1",
"firstName": "Jackie",
"lastName": "Chan",
"marks": [ 4, 2 ]
}
]
}
]
}
]
Function which transforms json document:
function transformData (groups) { // groups - array
let newGroups = [];
for (let group of groups) {
newGroup = {};
for (let key in group) {
if (key === 'students' || key === 'subjects') continue;
newGroup[key] = group[key];
}
newGroup.subjects = [];
for (let subject of group.subjects) {
let newSubject = {
name: subject.name,
dates: [],
students: []
};
for (let student of group.students) {
let index = newSubject.students.push(student) - 1;
newSubject.students[index].marks = [];
}
for (let lesson of subject.lessons) {
let index = newSubject.dates.push(lesson.date) - 1;
for (let mark of lesson.marks) {
for (let student of newSubject.students) {
if (student._id !== mark.student_id) continue;
while(student.marks.length !== index) {
student.marks.push(null);
}
student.marks.push(mark.value);
}
}
}
newGroup.subjects.push(newSubject);
}
newGroups.push(newGroup);
}
return newGroups;
}
How can I replace this function with mongodb aggregation?

creating new object with values of another object in javascript

How can we change the structure of the below data object using JavaScript. Needs to categorize all the names under the std. Thanks in advance
[
{
"name": "Rohan",
"std": "3"
},
{
"name": "Jack",
"std": "2"
},
{
"name": "Peter",
"std": "2"
}
]
to
[
{
"std": "2",
"details": [
{
"name": "Jack"
},
{
"name": "Peter"
}
]
},
{
"std": "3",
"details": [
{
"name": "Rohan"
}
]
}
]
The solution using Array.forEach, Array.map and Object.keys functions:
var arr = [{"name": "Rohan", "std": "3"}, { "name": "Jack", "std": "2" }, { "name": "Peter", "std": "2" }],
grouped = {}, result;
arr.forEach(function(obj){
var std = obj['std'];
if (this[std]) {
this[std]['details'].push({'name' : obj['name']});
} else {
this[std] = {'std' : std, 'details' : [{'name' : obj['name']}]};
}
}, grouped);
result = Object.keys(grouped).map((k) => grouped[k]);
console.log(JSON.stringify(result, 0, 4));
The output:
[
{
"std": "2",
"details": [
{
"name": "Jack"
},
{
"name": "Peter"
}
]
},
{
"std": "3",
"details": [
{
"name": "Rohan"
}
]
}
]
You can use reduce() method here
var data = [{
"name": "Rohan",
"std": "3"
}, {
"name": "Jack",
"std": "2"
}, {
"name": "Peter",
"std": "2"
}],
res = [],
kmap = {};
res = data.reduce(function(a, b) {
// check std value already in array using kmap object
if (kmap[b.std]) {
// if already exist then push name attribute in the details
a[kmap[b.std] - 1].details.push({
'name': b.name
});
} else {
// in else case push the new object
a.push({
'std': b.std,
'details': [{
'name': b.name
}]
});
kmap[b.std] = a.length; // storing the (index + 1) value to avoid 0 in if condition
}
return a;
}, []);
console.log(res);
For older browsers check polyfill option for reduce method.
Problems like this are good candidates for recursion. Here is one possible recursive solution. You can make it much prettier using a functional programming framework such as underscore.js.
var objs = [
{
"name": "Rohan",
"std": "3"
},
{
"name": "Jack",
"std": "2"
},
{
"name": "Peter",
"std": "2"
}
];
function categorize(objs) {
if (objs.length === 0) {
return [];
} else {
var first = objs.shift();
var categorized = categorize(objs);
for(var i = 0; i < categorized.length; i++) {
if (categorized[i].std === first.std) {
categorized[i].details.push({name: first.name});
break;
}
}
if(i === categorized.length) {
categorized.push({std: first.std, details: [{name: first.name}]});
}
return categorized;
}
}
var res = categorize(objs);
console.log(res);
If you're using lodash (I know the question didn't ask this and it's going to be slower, but it may be useful to someone :))
var data = [
{ "name": "Rohan", "std": "3" },
{ "name": "Jack", "std": "2" },
{ "name": "Peter", "std": "2" }
];
var grouped = _.chain(data)
.groupBy('std')
.map(function (people, std) {
return {
std: std,
details: _.map(people, function(person) {
return { name: person.name };
})
}
}).value();

Underscore Convert array to object keys

I am trying to convert this array to an object. Using underscore, I want to convert this array :
[
{
"id": "parentA",
"children": [
{
"name": "name1"
},
{
"name": "name2"
},
{
"name": "name3"
}
]
},
{
"id": "parentB",
"children": [
{
"name": "name4"
},
{
"name": "name5"
},
{
"name": "name6"
}
]
}]
into an object that looks like this:
{
"name1": "parentA",
"name2": "parentA",
"name3": "parentA",
"name4": "parentB",
"name5": "parentB",
"name6": "parentB"
}
I'm really just looking for the cleanest/simplest way possible.
Here's a fairly short way to do it with two reduce:
var data = [
{
"id": "parentA",
"children": [
{
"name": "name1"
},
{
"name": "name2"
},
{
"name": "name3"
}
]
},
{
"id": "parentB",
"children": [
{
"name": "name4"
},
{
"name": "name5"
},
{
"name": "name6"
}
]
}];
var out = _.reduce(data, function(result, parent) {
_.reduce(parent.children, function(r, child) {
r[child.name] = parent.id;
return r;
}, result);
return result;
}, {});
document.write(JSON.stringify(out));
<script src="http://underscorejs.org/underscore-min.js"></script>
var a = [{
"id": "parentA",
"children": [{
"name": "name1"
}, {
"name": "name2"
}, {
"name": "name3"
}]
}, {
"id": "parentB",
"children": [{
"name": "name4"
}, {
"name": "name5"
}, {
"name": "name6"
}]
}];
var new_obj = {};
var len = a.length;
for (j = 0; j < len; j++) {
var c = $.extend({}, a[j]);
var children_length = (c.children).length;
for (i = 0; i < children_length; i++) {
var temp = ((a[j].children)[i]).name;
new_obj[temp] = c.id;
}
}
document.write(JSON.stringify(new_obj));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You'll only need to use underscore if you're supporting browsers without native reduce and forEach array methods, but you can do it like this.
var result = _.reduce(array, function(memo, entry) {
_.each(entry.children, function(child) {
memo[child.name] = entry.id;
});
return memo;
}, {});
function expand(list){
return _.reduce(list,function(a,b) {
_.each(b.children, function(c) {
a[c.name] = b.id;
});
return a;
},{});
}
Check the output for your sample here

Categories

Resources