formatting data into a new structure javascript - javascript

I am working with D3 at the moment as an experiment, I recieve data from an API in a certain format, but I need to retructure that data into format that works with D3 below is an example of the data that I am receiving.
{
"user_id": 3,
"service_user": "Phillippa",
"staff_name": "Abbey",
"role": "A",
"staff_id": 2,
"status": "P",
"workbase": "Workbase 1"
},
{
"user_id": 60,
"service_user": "Raymond",
"staff_name": "Adam",
"role": "D",
"staff_id": 8,
"status": "C",
"workbase": "Workbase 2"
},
{
"user_id": 63,
"service_user": "Alison",
"staff_name": "Adam",
"role": "D",
"staff_id": 8,
"status": "C",
"workbase": "Workbase 2"
},
{
"user_id": 68,
"service_user": "Philippa",
"staff_name": "Adam",
"role": "C",
"staff_id": 9,
"status": "C",
"workbase": "Workbase 2"
},
{
"user_id": 57,
"service_user": "Philip",
"staff_name": "Adam",
"role": "W",
"staff_id": 9,
"status": "C",
"workbase": "Workbase 2"
}
The strucutre D3 is expecting is following,
{
"name":"flare",
"children":[
{
"name":"analytics",
"children":[
{
"name":"cluster",
"children":[
{
"name":"AgglomerativeCluster",
"size":3938
},
{
"name":"CommunityStructure",
"size":3812
},
{
"name":"HierarchicalCluster",
"size":6714
},
{
"name":"MergeEdge",
"size":743
}
]
},
{
"name":"graph",
"children":[
{
"name":"BetweennessCentrality",
"size":3534
},
{
"name":"LinkDistance",
"size":5731
},
{
"name":"MaxFlowMinCut",
"size":7840
},
{
"name":"ShortestPaths",
"size":5914
},
{
"name":"SpanningTree",
"size":3416
}
]
},
{
"name":"optimization",
"children":[
{
"name":"AspectRatioBanker",
"size":7074
}
]
}
]
}
]
}
So I need to use the received data to produce a new structure which is basically objects with children arrays.
The way the first structure works is that Workbase 1, has 1 child "Abbey", and in turn "Abbey" has 1 child "Phillipa", now it maybe that Workbase 1 appears many times in the returned data, so all it needs pushing into a Workbase 1 specific object.
Workbase 2 is slightly more complex, Workbase 2 has 1 child "Adam" and "Adam" has 4 children "Raymond", "Allison", "Phillipa" and "Phillip".
Theoretically the data should look like this,
{
"name":"Workbase 1",
"children":[
{
"name":"Abbey",
"children":[
{
"name":"Phillipa"
}
]
}
]
},
{
"name":"Workbase 2",
"children":[
{
"name":"Adam",
"children":[
{
"name":"Raymond"
},
{
"name":"Allison"
},
{
"name":"Phillipa"
},
{
"name":"Phillip"
}
]
}
]
}
So far I am looping through the object and making sure I am only getting unique workbases,
original_data.forEach(function(j){
if(_.indexOf(workbases, j.workbase) < 0) {
workbases.push(j.workbase);
data.push({
name : j.workbase,
children : []
});
}
});
From this point I cannot work out to get the correct children and childrens children into the correct workbase, any ideas?

let sorted = original_data.reduce((acc, cur) => {
/* check if the workbase is already in the array */
let wb = acc.find(wb => wb.name === cur.workbase);
if (wb) {
/* check if staff by that name is already in this workbase */
let staff = wb.children.find(staff => staff.name === cur.staff_name);
if (staff) {
staff.children.push({name: cur.service_user});
} else {
/* if not, instantiate this staff in the array */
wb.push({
name: cur.staff_name,
children: [{name: cur.service_user}]
});
}
} else {
/* if not, instantiate this workbase in the array */
acc.push({
name: cur.workbase,
children: [
{
name: cur.staff_name,
children: [{name: cur.service_user}]
}
]
});
}
return acc;
}, []);

You could use a nested approach with a hash table for the names.
var data = [{ "user_id": 3, "service_user": "Phillippa", "staff_name": "Abbey", "role": "A", "staff_id": 2, "status": "P", "workbase": "Workbase 1" }, { "user_id": 60, "service_user": "Raymond", "staff_name": "Adam", "role": "D", "staff_id": 8, "status": "C", "workbase": "Workbase 2" }, { "user_id": 63, "service_user": "Alison", "staff_name": "Adam", "role": "D", "staff_id": 8, "status": "C", "workbase": "Workbase 2" }, { "user_id": 68, "service_user": "Philippa", "staff_name": "Adam", "role": "C", "staff_id": 9, "status": "C", "workbase": "Workbase 2" }, { "user_id": 57, "service_user": "Philip", "staff_name": "Adam", "role": "W", "staff_id": 9, "status": "C", "workbase": "Workbase 2" }],
result = [];
data.forEach(function (a) {
var check = function (key, target) {
if (!this[key]) {
this[key] = { name: key, children: [] };
target.push(this[key]);
}
}.bind(this);
check(a.workbase, result);
check(a.staff_name, this[a.workbase].children);
this[a.staff_name].children.push({ name: a.service_user });
}, Object.create(null));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

how to change the format of json array by loping over

Hi I am getting data from API but I want my data in different format so that I can pass later into a function. I want to change the names of keys into a different one becasuse I have created a chart and it only draws if I send it data in certain way
This is what I am getting from API
data = {
"status": "success",
"from": "DB",
"indice": "KSE100",
"data": [
{
"stock_sector_name": "Tc",
"sector_score": "0828",
"stocks": [
{
"stock_symbol": "TRG",
"stock_score": 44
},
{
"stock_symbol": "SYS",
"stock_score": 33
}
]
},
{
"stock_sector_name": "OIL",
"sector_score": "0828",
"stocks": [
{
"stock_symbol": "FFS",
"stock_score": 44
},
{
"stock_symbol": "SMS",
"stock_score": 33
}
]
},
]
}
But I want my data to look like this like this
data = {
"name": "KSE100",
"children": [
{
"name": "A",
'points': -9,
"children": [
{
"stock_title": "A",
"value": 12,
},
{
"stock_title": "B",
"value": 4,
},
]
},
{
"name": "B",
'points': 20,
"children": [
{
"stock_title": "A",
"value": 12,
},
{
"name": "B",
"value": 4,
},
]
},
]
}
Like I want to replace
stock_sector_name = name
sector_score = value
stocks = children
stock_symbol = name
stock_score = value
I have been trying this for so much time but sill could not figured it out
function convert(d){
return {
name : d.indice,
children : d.data.map(y=>{
return {
name : y.stock_sector_name,
points : y.sector_score,
children : y.stocks.map(z=>{
return {
stock_title: z.stock_symbol,
value : z.stock_score
}
})
}
})
}
}
You can do something like this
const data = {
"status": "success",
"from": "DB",
"indice": "KSE100",
"data": [{
"stock_sector_name": "Tc",
"sector_score": "0828",
"stocks": [{
"stock_symbol": "TRG",
"stock_score": 44
},
{
"stock_symbol": "SYS",
"stock_score": 33
}
]
},
{
"stock_sector_name": "OIL",
"sector_score": "0828",
"stocks": [{
"stock_symbol": "FFS",
"stock_score": 44
},
{
"stock_symbol": "SMS",
"stock_score": 33
}
]
},
]
}
const data2 = {
"name": "KSE100",
"children": [{
"name": "A",
'points': -9,
"children": [{
"stock_title": "A",
"value": 12,
},
{
"stock_title": "B",
"value": 4,
},
]
},
{
"name": "B",
'points': 20,
"children": [{
"stock_title": "A",
"value": 12,
},
{
"name": "B",
"value": 4,
},
]
},
]
}
//stock_sector_name = name
//sector_score = value
//stocks = children
//stock_symbol = stock_title
//stock_score = value
const keys = {
stock_sector_name: "name",
sector_score: "points",
stocks: "children",
stock_symbol: "stock_title",
stock_score: "value",
indice: "name",
//data: "children"
}
const rename = (value) => {
if (!value || typeof value !== 'object') return value;
if (Array.isArray(value)) return value.map(rename);
return Object.fromEntries(Object
.entries(value)
.map(([k, v]) => [keys[k] || k, rename(v)])
);
}
renamedObj = rename(data);
console.log(renamedObj);

How can I reshape this nested JSON data?

This is essentially what the payload looks like from my API. I'd like to reshape the data so I can dynamically display the data on the frontend without hard coding things like column names. For what it's worth I'm using DRF, axios, and react-redux. That said I think I just need to learn more vanilla js :/
*purposely have a different number of keys in 1 entry vs another.
data =[
{
"id": 1,
"j_column": {
"name": "James",
"outside_id": 1,
"alt_name": "Jim",
"full_name": "James the third"
}
},
{
"id": 3,
"j_column": {
"name": "Dennis",
"outside_id": 57,
"alt_name": "Denny",
"full_name": "Dennis the third",
"nickname": "Denny the super star"
}
}]
newData =[
{
"id": 1,
"name": "James",
"outside_id": 1,
"alt_name": "Jim",
"full_name": "James the third"
},
{
"id": 3,
"name": "Dennis",
"outside_id": 57,
"alt_name": "Denny",
"full_name": "Dennis the third",
"nickname": "Denny the super star"
}]
This is one way to do it:
const data =[
{
"id": 1,
"j_column": {
"name": "James",
"outside_id": 1,
"alt_name": "Jim",
"full_name": "James the third"
}
},
{
"id": 3,
"j_column": {
"name": "Dennis",
"outside_id": 57,
"alt_name": "Denny",
"full_name": "Dennis the third",
"nickname": "Denny the super star"
}
}];
const newData = data.map((el) => {
const obj = {...el.j_column};
obj.id = el.id;
return obj;
});
console.log(newData);
var new_data = [];
data.map(item => {
var obj = {};
Object.keys(item).map(itemKey => {
if (typeof item[itemKey] !== 'object') {
obj[itemKey] = item[itemKey]
}else
Object.keys(item[itemKey]).map(subItemKey => {
obj[subItemKey] = item[itemKey][subItemKey]
})
})
new_data.push(obj);
})
console.log(new_data);

Sort Array of Objects Childs to new Array with Objects

I'm programming a small vue.js App and need to convert an array to a new one and sort them.
The array of objects I get from the backend server looks like that:
var arr =
[
{
"id": 1,
"name": "Name1",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 10
}
}
},
{
"id": 2,
"name": "Name2",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 11
}
}
},
{
"id": 3,
"name": "Name3",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 10
}
}
}
]
console.log(arr)
But I need a new array, that is sorted like that:
var newArr =
[
{
"mainId": 10,
"parents": {
"id": 1,
"name": "Name1"
}
},
{
"mainId": 11,
"parents": [
{
"id": 2,
"name": "Name2"
},
{
"id": 3,
"name": "Name3"
}
]
}
]
What is the best way to implement this?
You could group the items with the help of a Map.
var array = [{ id: 1, name: "Name1", parents: { someOtherTings: "Test", partentOfParent: { mainId: 10 } } }, { id: 2, name: "Name2", parents: { someOtherTings: "Test", partentOfParent: { mainId: 11 } } }, { id: 3, name: "Name3", parents: { someOtherTings: "Test", partentOfParent: { mainId: 10 } } }],
result = Array.from(
array.reduce(
(m, { id, name, parents: { partentOfParent: { mainId } } }) =>
m.set(mainId, [...(m.get(mainId) || []), { id, name }]),
new Map
),
([mainId, parents]) => ({ mainId, parents })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You just need a combination of map to create a new array and then sort it based on the mainId value
var arr = [{
"id": 1,
"name": "Name1",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 10
}
}
},
{
"id": 2,
"name": "Name2",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 11
}
}
},
{
"id": 3,
"name": "Name3",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 10
}
}
}
]
const newArr = arr.map(obj => ({
mainId: obj.parents.partentOfParent.mainId,
parents: {
id: obj.id,
name: obj.name
},
})).sort((a, b) => b - a);
console.log(newArr);

multi level groupby ramda js

I have been trying to use group by at multiple levels so that the object is grouped by tag, folder and report keys. I was able to groupby at single level but could not proceed further.
const data = [{
"_index": "search_index",
"_type": "search_type",
"_id": "Co5EFxnqeo9ruq",
"_score": 1,
"_source": {
"admin_tags": [],
"type": "human",
"folder": "Feature Samples",
"url_t": "url_tdata",
"users": [
128
],
"agent_id": 2,
"url": "url_data",
"favorited_by": [20],
"idx": 121,
"path": "Report Samples//Feature Samples",
"name": "Grouping and Sorting",
"description": ""
}
}];
const mapIndexed = R.addIndex(R.map);
const tg = mapIndexed((x, i) => ({
"name": x._source.admin_tags[0] == undefined ? "Unclasified" : x._source.admin_tags[0],
"idx": i,
"folder": [{
"name": x._source.folder,
"idx": x._source.folder,
"report": [{
"agent_id": x._source.agent_id,
"description": x._source.description,
"favorited_by": x._source.favorited_by[0],
"name": x._source.name,
"idx": x._source.idx,
"path": x._source.path,
"type": x._source.type,
"url": x._source.url,
"url_t": x._source.url_t,
}]
}]
}), data);
const byTag = R.groupBy(data => data.name)
const tagged = byTag(tg);
console.log(tagged)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.24.1/ramda.min.js"></script>
This is the output I am trying to achieve with grouping at three levels and values of user_report_id, views always set to zero.
const output = {
"message": "",
"payload": [{
"name": "Unclasified",
"idx": 0,
"folders": [{
"idx": "Feature Samples",
"name": "Feature Samples",
"reports": [{
"agent_id": 2,
"description": "",
"idx": 121,
"is_fav": 20,
"name": "Grouping and Sorting",
"type": "human",
"url": "url_data",
"url_t": "url_tdata",
"user_report_id": 0,
"views": 0,
"report_id": '2sdfsd'
}]
}]
}]
}
There might be a better/built in solution, but you can use map to group the "inner lists" of your objects like so:
const data = [
{ letter: "a", number: 1, bool: true },
{ letter: "a", number: 2, bool: true },
{ letter: "a", number: 2, bool: false },
{ letter: "b", number: 1, bool: true },
{ letter: "b", number: 1, bool: false },
{ letter: "b", number: 1, bool: false },
{ letter: "c", number: 1, bool: true },
{ letter: "c", number: 2, bool: true },
{ letter: "c", number: 2, bool: false },
{ letter: "c", number: 2, bool: true },
];
const groupByLetterNumberBool = pipe(
groupBy(prop("letter")),
map(groupBy(prop("number"))),
map(map(groupBy(prop("bool"))))
);
groupByLetterNumberBool(data);
Working example here.

Create new array with another structure in Javascript

I want to create a new array based on an original array but with merged data.
Every name key need to have merged date+time (format: YYYY-MM-DD HH:MM) with merged scores. All unique datetimes need to be available as key for each name.
ARRAY ORIGINAL:
"data": [{
"name": "A",
"history": [{
"created": "2017-05-16 00:00:00",
"score": "1"
},
{
"created": "2017-05-16 00:01:10",
"score": "1"
},
{
"created": "2017-05-16 00:01:30",
"score": "1"
}
]
},
{
"name": "B",
"history": [{
"created": "2017-05-16 00:01:00",
"score": "1"
}]
}
]
ARRAY THAT I WANT:
{
[A]: {
"2017-05-16 00:00": 1,
"2017-05-16 00:01": 2
},
[B]: {
"2017-05-16 00:00": 0,
"2017-05-16 00:01": 1
}
}
I hope you guys can help me out. I can't even think of an efficiƫnt way to do this, unfortunately. I tried to solve this issue with 5 foreach statements with no luck :(
You could use two arrays for names and times as closure and generate for all names and times a property with zero value.
var data = { data: [{ name: "A", history: [{ created: "2017-05-16 00:00:00", score: "1" }, { created: "2017-05-16 00:01:10", score: "1" }, { created: "2017-05-16 00:01:30", score: "1" }] }, { name: "B", history: [{ created: "2017-05-16 00:01:00", score: "1" }] }] },
result = data.data.reduce(function (names, times) {
return function (r, a) {
if (!r[a.name]) {
r[a.name] = {};
times.forEach(function (time) {
r[a.name][time] = 0;
});
names.push(a.name);
}
a.history.forEach(function (o) {
var time = o.created.slice(0, 16);
if (times.indexOf(time) === -1) {
names.forEach(function (name) {
r[name][time] = 0;
});
times.push(time);
}
r[a.name][time] += +o.score;
});
return r;
};
}([], []), {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You have to create an object not an array, As arrays cannot have a key-value pair in javascript. There is no associative array concept in javascript. You have to use objects in javascript for that.
Here is how you can do what you are trying to achieve using objects.
value = {
"data": [{
"name": "A",
"history": [{
"created": "2017-05-16 00:00:00",
"score": "1"
},
{
"created": "2017-05-16 00:01:10",
"score": "1"
},
{
"created": "2017-05-16 00:01:30",
"score": "1"
}
]},
{
"name": "B",
"history": [{
"created": "2017-05-16 00:01:00",
"score": "1"
}]
}]
};
var result ={};
value.data.forEach(function(v){
var score = {};
for(var i=0;i<v.history.length;i++){
score[v.history[i].created] = v.history[i].score;
}
result[v.name] = score;
});
console.log(result);
Now you can access data as result.A or result[A] and result.B or result[B]
SNIPPET
value = {
"data": [{
"name": "A",
"history": [{
"created": "2017-05-16 00:00:00",
"score": "1"
},
{
"created": "2017-05-16 00:01:10",
"score": "1"
},
{
"created": "2017-05-16 00:01:30",
"score": "1"
}
]
},
{
"name": "B",
"history": [{
"created": "2017-05-16 00:01:00",
"score": "1"
}]
}
]
};
var result = {};
value.data.forEach(function(v) {
var score = {};
for (var i = 0; i < v.history.length; i++) {
score[v.history[i].created] = v.history[i].score;
}
result[v.name] = score;
});
console.log(result);

Categories