Map Json Data to new key-value pair JavaScript object - javascript

I want to map one json data to a new javascript object like following. Here the json data is dynamic and can have more files with more users. The group information is new and it depends on parent-child information. Can anyone please help me out? Thank you for your time.
Before:
{
"userinfo": {
"/home/user/main/sub/info/1stfile.txt": {
"John": "something",
"Mike": "something",
"Merry": "something",
"Susan": "something"
},
"/home/user/main/info/2ndfile.txt": {
"Mulan": "something",
"James": "something"
},
"/home/user/main/info/3rdfile.txt": {
"Nancy": "something"
},
"/home/user/main/4thfile.txt": {
"Kamal": "something",
"Xian": "something",
"Mila": "something"
}
}
}
After:
{
"name": "main",
"children": [
{
"name": "1stfile",
"children": [
{
"name": "John",
"group": "1"
},
{
"name": "Mike",
"group": "1"
},
{
"name": "Merry",
"group": "1"
},
{
"name": "Susan",
"group": "1"
}
],
"group": 1
},
{
"name": "2ndfile",
"children": [
{
"name": "Mulan",
"group": 2
},
{
"name": "James",
"group": 2
}
],
"group": 2
},
{
"name": "3rdfile",
"children": [
{
"name": "Nancy",
"group": 3
}
],
"group": 3
},
{
"name": "4thfile",
"children": [
{
"name": "Kamal",
"group": 4
},
{
"name": "Xian",
"group": 4
},
{
"name": "Mila",
"group": 4
}
],
"group": 4
}
],
"group": 0
}
I was trying to build one block of parent-child by using following code
var jsonData = json["userinfo"];
var keys = Object.keys(jsonData);
console.log(keys);
let data = {};
for (var j = 0; j < keys.length; j++) {
let g = 1;
data[j] = { name: keys[j], group: g++ };
}
console.log(data);
Which is giving following output
{
0: {
"name": "/home/user/main/sub/info/1stfile.txt",
"group": 1
},
1: {
"name": "/home/user/main/info/2ndfile.txt",
"group": 1
},
2: {
"name": "/home/user/main/info/3rdfile.txt",
"group": 1
},
3: {
"name": "/home/user/main/4thfile.txt",
"group": 1
}
}
The value is assigning properly but is creating extra keys (0,1,2,3)!

Assuming you need something like this.
You can utilize Array.map() and Object.keys() function for your operation.
<script>
const beforeJSON = `{
"userinfo": {
"/home/user/main/sub/info/1stfile.txt": {
"John": "something",
"Mike": "something",
"Merry": "something",
"Susan": "something"
},
"/home/user/main/info/2ndfile.txt": {
"Mulan": "something",
"James": "something"
},
"/home/user/main/info/3rdfile.txt": {
"Nancy": "something"
},
"/home/user/main/4thfile.txt": {
"Kamal": "something",
"Xian": "something",
"Mila": "something"
}
}
}`
const before = JSON.parse(beforeJSON);
const filenames = Object.keys(before.userinfo);
const after = {
name: 'main',
children: [],
group: 0,
}
const children = filenames.map((filename, idx) => {
const innerChildren = Object.keys(before.userinfo[filename]).map((n) => ({
name: n,
group: idx + 1,
}))
return ({
name: filename,
children: innerChildren,
group: idx + 1,
});
})
after.children = children;
console.log(after);
</script>
Please format your code next time before posting another question.

Related

How can I inner join with two object arrays in JavaScript?

I need inner join with two array in javascript like this:
array1 =
[
{
"id": 1,
"name": "Tufan"
},
{
"id": 2,
"name": "Batuhan"
},
{
"id": 3,
"name": "Hasan"
}
]
array2 =
[
{
"name": "yyy",
"externalid": "1",
"value": "Asd"
},
{
"name": "aaaa"
"externalid": "2",
"value": "ttt"
}
]
expectedArray =
[
{
"id": 1,
"name": "Tufan",
"externalid": "1",
"value": "Asd"
},
{
"id": 2,
"name": "Batuhan",
"externalid": "2",
"value": "ttt"
}
]
rules:
on: array2.externalid = array1.id
select: array1.id, array1.name, array2.externalid, array2.value
My approach:
array1.filter(e => array2.some(f => f.externalid == e.id));
// I need help for continue
How can I make this?
Doesn't matter information: I use ES5 and pure javascript
You can do it like this:
const res = array2.map((item) => {
const related = array1.find((el) => el.id == item.externalid);
return { ...item, ...related };
});
Using a map to loop over the array2 and a find to get the array1 relative.

Filtering an array based on multiple arrays inputs

I have three arrays.
1. Existing viewers array - existingViewers
New viewers array - newViewers
Permitted Viewers array - permittedViewers
permittedViewers is used for rendering the drop-down. And I wish to filter the newViewers and existingViewers entries from the permittedViewers.
I am doing this as three steps. And I am afraid this is not the optimized way. Can someone suggest the ideal way of doing this?
The expected result is
[
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let existingViewers = [{
"viewerId": 1,
"name": "name1"
},
{
"viewerId": 2,
"name": "name2"
}
],
newViewers = [
{
"viewerId": 3,
"name": "name3"
}
],
permittedViewers = [{
"id": 1,
"name": "name1"
},
{
"id": 2,
"name": "name2"
},
{
"id": 3,
"name": "name3"
},
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let grouped = [...existingViewers, ...newViewers]
let viewerFilter = grouped.map(viewer => { return viewer.viewerId; });
let filteredPermittedViewers = permittedViewers.filter(viewer => !viewerFilter.includes(viewer.id));
console.log(filteredPermittedViewers)
I'd make a Set of the ids of the first two arrays, and then filter the third by whether the set includes the id. (Sets have O(1) lookup time)
let existingViewers=[{"viewerId":1,"name":"name1"},{"viewerId":2,"name":"name2"}],newViewers=[{"viewerId":3,"name":"name3"}],permittedViewers=[{"id":1,"name":"name1"},{"id":2,"name":"name2"},{"id":3,"name":"name3"},{"id":4,"name":"name4"},{"id":5,"name":"name5"},{"id":6,"name":"name6"}];
const ids = new Set([...existingViewers, ...newViewers].map(({ viewerId }) => viewerId));
const output = permittedViewers.filter(({ id }) => !ids.has(id));
console.log(output);
You can compress all three statements into a single statement -- just replace the variable name with the statement that creates it:
let existingViewers = [{
"viewerId": 1,
"name": "name1"
},
{
"viewerId": 2,
"name": "name2"
}
],
newViewers = [
{
"viewerId": 3,
"name": "name3"
}
],
permittedViewers = [{
"id": 1,
"name": "name1"
},
{
"id": 2,
"name": "name2"
},
{
"id": 3,
"name": "name3"
},
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let filteredPermittedViewers = permittedViewers.filter(viewer => ! [...existingViewers, ...newViewers].map(viewer => viewer.viewerId).includes(viewer.id));
console.log(filteredPermittedViewers)

Ramda to loop over array

Loop may be the wrong term, but it kind of describes what I am attempting.
I want to give structure to flat data, but I also need to keep track of the array it came from.
Basically my rules are (per array):
If level 1 exists- give it the name of the item, and a typechild array. EACH time a level 1 appears (even in the same array) it should create a new entry.
Inside typechild, put the any items with level >1
If NO level 1 exists- give it the name of the item, and a typechild array.
My code below is almost there, with the exception that it should create an array EVERYTIME it sees a level 1. My example will make sense:
Input data
[
{
"title": "Test 1",
"type": [{
"name": "Animal",
"level": 1
},
{
"name": "Food",
"level": 1
},
{
"name": "Chicken",
"level": 3
}
]
},
{
"title": "Test 2",
"type": [{
"name": "Foo",
"level": 2
}]
}
]
Note: Animal and Food are both LEVEL 1 items. So it should create two ARRAYS like so...
Desired output
[
{
name: "Animal",
typechild: [
{
level: 2,
name: "Chicken"
}
]
},
{
name: "Food",
typechild: [
{
level: 2,
name: "Chicken"
}
]
},
{
name: "NoName",
typechild: [
{
level: 2,
name: "Foo"
}
]
}
]
Ramda attempt (try here: https://dpaste.de/JQHw):
const levelEq = (n) => pipe(prop('level'), equals(n));
const topLevel = pipe(prop('type'), find(levelEq(1)));
const topLevelName = pipe(topLevel, propOr('NoName', 'name'));
const extract2ndLevel = pipe(pluck('type'), flatten, filter(levelEq(2)));
const convert = pipe(
groupBy(topLevelName),
map(extract2ndLevel),
map(uniq),
toPairs,
map(zipObj(['name', 'typechild']))
);
Something like this?
var output = [{
"name": "Animal",
"typechild": [{
"name": "Chicken",
"level": 3
}, {
"name": "Dog",
"level": 2
}]
}, {
"name": "Food",
"typechild": [{
"name": "Chicken",
"level": 3
}]
}, {
"name": "No name",
"typechild": [{
"name": "Foo",
"level": 2
}, {
"name": "Baz",
"level": 2
}]
}]
let out = {},
typechild = {},
k;
const data = [{
"title": "Test 1",
"type": [{
"name": "Animal",
"level": 1
}, {
"name": "Food",
"level": 1
}, {
"name": "Chicken",
"level": 3
}]
}, {
"title": "Test 2",
"type": [{
"name": "Foo",
"level": 2
}]
}, {
"title": "Test 3",
"type": [{
"name": "Baz",
"level": 2
}]
}, {
"title": "Test 4",
"type": [{
"name": "Animal",
"level": 1
}, {
"name": "Dog",
"level": 2
}]
}]
data.forEach((node) => {
k = false;
typechild[node.title] = [];
node.type && node.type.forEach((t, i) => {
if (t.level == 1) {
k = true;
!out[t.name] ? out[t.name] = {
name: t.name,
typechild: typechild[node.title]
} : out[t.name].typechild = out[t.name].typechild.concat(typechild[node.title]);
} else {
typechild[node.title].push(t);
}
if (i == node.type.length - 1 && !k && typechild[node.title].length) {
out['No name'] = out['No name'] || {
name: 'No name',
typechild: []
};
out['No name'].typechild = out['No name'].typechild.concat(typechild[node.title]);
}
});
});
console.log(JSON.stringify(Object.values(out)));

Building new JSON from existing one

I want to build an new JSON from existing one. The source has sections and rubrics that I no longer need for a listing. The new object called 'items' should have an array of the items.
The final JSON should be sorted by attribute 'name' and look like
{
"items": [
{
"id": 10000006,
"name": "Boah"
},
{
"id": 10000013,
"name": "Gut"
},
{
"id": 10000003,
"name": "Ipsum"
},
{
"id": 10000001,
"name": "Lorem"
},
{
"id": 10000005,
"name": "Lorum"
},
{
"id": 10000004,
"name": "Name"
},
{
"id": 10000002,
"name": "Stet"
}
]
}
For building the new JSON I get this source:
{
"sections": [
{
"name": "FooBar",
"rubrics": [
{
"name": "Foo",
"items": [
{
"id": 10000001,
"name": "Lorem"
},
{
"id": 10000002,
"name": "Stet"
},
{
"id": 10000003,
"name": "Ipsum"
}
]
},
{
"name": "Bar",
"items": [
{
"id": 10000004,
"name": "Name"
},
{
"id": 10000005,
"name": "Lorum"
},
{
"id": 10000006,
"name": "Boah"
}
]
}
]
},
{
"name": "BlahBloob",
"rubrics": [
{
"name": "Bla",
"items": [
{
"id": 10000013,
"name": "Gut"
}
]
},
{
"name": "Bloob",
"items": [
{
"id": 10000014,
"name": "Name"
},
{
"id": 10000015,
"name": "Lorem"
}
]
}
]
}
]
}
What do you think? How can I do this with plain JavaScript or maybe TypeScript?
Thanks for reading and have time for my question. And thanks for reply in advance.
Here you go. You just need to iterate over each rubric of each section of your source to get the items. At the end, sort your list of items by items, and you're done.
This example uses ES6 syntax, but it's easy to convert it to ES5 if needed.
function extractItems(source) {
const items = [];
for (const section of source.sections) {
for (const rubric of section.rubrics) {
items.push(...rubric.items);
}
}
items.sort((a, b) => a.name.localeCompare(b.name));
return { items };
}
A more functional approach use map and reduce to pick the rubrics and merge them.
data.sections
.map(section => section.rubrics) // get rubrics
.reduce((a, b) => a.concat(b)) // merge rubrics
.map(rubric => rubric.items) // get items from each rubric
.reduce((a, b) => a.concat(b)) // merge items
.sort((a, b) => a.name.localeCompare(b.name)); // sort
function(oldObj) {
var newObj = {
"items": []
};
oldObj.sections.forEach(function(section) {
section.rubrics.forEach(function(rubric) {
rubric.items.forEach(function(item) {
newObj.items.push(item);
});
});
});
newObj.items = newObj.items.sort(function(a, b) {
if (a.name < b.name) { return -1; }
if (a.name > b.name) { return 1; }
return 0;
});
return newObj;
}
And simply use JSON.parse() and JSON.stringify() to convert JSON to and from objects.
It might help you
var data ={
"sections": [
{
"name": "FooBar",
"rubrics": [{"name": "Foo", "items": [{"id": 10000001,"name": "Lorem"}, {"id": 10000002,"name": "Stet"}, {"id": 10000003,"name": "Ipsum"}]
}, {
"name": "Bar",
"items": [{
"id": 10000004,
"name": "Name"
}, {
"id": 10000005,
"name": "Lorum"
}, {
"id": 10000006,
"name": "Boah"
}]
}]
}, {
"name": "BlahBloob",
"rubrics": [{
"name": "Bla",
"items": [{
"id": 10000013,
"name": "Gut"
}]
}, {
"name": "Bloob",
"items": [{
"id": 10000014,
"name": "Name"
}, {
"id": 10000015,
"name": "Lorem"
}]
}]
}]
};
var itemObj = {};
var itemArr = [];
var sections = data.sections;
for(var i=0;i<sections.length;i++)
{
for(var j=0;j<sections[i].rubrics.length;j++){
for(var k=0;k<sections[i].rubrics[j].items.length;k++){
var itemObj;
itemObj['id'] = sections[i].rubrics[j].items[k].id;
itemObj['name'] = sections[i].rubrics[j].items[k].name;
itemArr.push(itemObj);
}
}
}
var finalObj = {"items":itemArr};
console.log(finalObj);
JSFiddle

Making one to many relation array in JavaScript

I have two arrays of objects:
var a = [{
"id": 1,
"name": "q"
},
{
"id": 2,
"name": "l"
}]
and another is
var b = [{
"id": 3,
"sub": 1,
"name": "ni"
},
{
"id": 4,
"sub": 2,
"name": "bh"
}]
Here sub is the id in a
I need to have a new array which will look like this:
var c = [
{
"id":1,
"name":"q",
"map":[
{
"id":3,
"name":"ni"
}
]
},
{
"id":2,
"name":"l",
"map":[
{
"id":4,
"name":"bh"
}
]
}
]
How can I do that in JavaScript?
I am using underscore in my project.
In plain Javascript you could use Array#map, Array#forEach and a hash table.
var a = [{ "id": 1, "name": "q" }, { "id": 2, "name": "l" }],
b = [{ "id": 3, "sub": 1, "name": "ni" }, { "id": 4, "sub": 2, "name": "bh" }],
hash = Object.create(null),
result = a.map(function (a, i) {
hash[a.id] = { id: a.id, name: a.name };
return hash[a.id];
}, hash);
b.forEach(function (a) {
hash[a.sub].map = hash[a.sub].map || [];
hash[a.sub].map.push({ id: a.id, name: a.name });
}, hash);
console.log(result);
ES6
var a = [{ "id": 1, "name": "q" }, { "id": 2, "name": "l" }],
b = [{ "id": 3, "sub": 1, "name": "ni" }, { "id": 4, "sub": 2, "name": "bh" }],
hash = Object.create(null),
result = a.map((hash => a => hash[a.id] = { id: a.id, name: a.name, map: [] })(hash));
b.forEach((hash => a => hash[a.sub].map.push({ id: a.id, name: a.name }))(hash));
console.log(result);
You can do it with the help of map function and then use the find function to search the data from the other array.
var b = [{
"id": 3,
"sub": 1,
"name": "ni"
}, {
"id": 4,
"sub": 2,
"name": "bh"
}];
var a = [{
"id": 1,
"name": "q"
}, {
"id": 2,
"name": "l"
}];
var final = _.map(b, function(d) {
return {
id: d.name,
name: d.name,
map: _.find(a, function(adata) {
return adata.id == d.sub; //use underscore find to get the relevant data from array a
})
}
});
console.log(final);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

Categories

Resources