How can I reshape this nested JSON data? - javascript

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);

Related

Get object value based on conditions within nested array objects

I have an array of objects called orders:
const orders = [
{
"order_id": 47445,
"order_type": "Wholesale",
"items": [
{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
}
]
}
];
I need to get the quantity when both the order_type (Wholesale) and items.detail.ID (13363) match.
I have so far tried the following:
const result = orders.find(item => item.order_type == "Wholesale").items
.reduce((total, item) => {
if(item.detail.ID == 13363) {
return item.quantity;
}
}, 0);
Where result correctly returns 4
My issue, and I'm sure I am missing something very simple is that when I have multiple items in my orders array, it fails.
const orders = [
{
"order_id": 47445,
"order_type": "Wholesale",
"items": [
{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
},
{
"id": 56,
"department": "Womens",
"type": "Skirt",
"quantity": 12,
"detail": {
"ID": 76884,
"On Sale": 0,
}
},
{
"id": 89,
"department": "Mens",
"type": "Shirts",
"quantity": 20,
"detail": {
"ID": 98223,
"On Sale": 1,
}
}
]
}
];
The same
const result = orders.find(item => item.order_type == "Wholesale").items
.reduce((total, item) => {
if(item.detail.ID == 13363) {
return item.quantity;
}
}, 0);
returns undefined
Thank you
The find helper just returns the first match, so you need to use another helper like filter, like this:
const ID = 13363;
const result = orders
.filter((order) => order.order_type === 'Wholesale')
.reduce((acc, curr) => {
const items = curr.items.filter((item) => item.detail.ID === ID);
console.log(items);
// You can sum the matching items and then push them into the acc array
const quantity = items.reduce((sum, item) => (sum += item.quantity), 0);
acc.push(quantity);
return acc;
}, []);
This will return an array of matching quantities.
Not sure about the use case but here you go
const result = orders.find(item => item.order_type == "Wholesale").items
.reduce((total, item) => {
if (item.detail.ID == 13363) {
total += item.quantity;
}
return total
}, 0);
You can even create a function to make the search dynamic.
const orders = [
{
"order_id": 47445,
"order_type": "Wholesale",
"items": [
{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
},
{
"id": 56,
"department": "Womens",
"type": "Skirt",
"quantity": 12,
"detail": {
"ID": 76884,
"On Sale": 0,
}
},
{
"id": 89,
"department": "Mens",
"type": "Shirts",
"quantity": 20,
"detail": {
"ID": 98223,
"On Sale": 1,
}
}
]
}
];
findMyItem=( ID )=>{
var result = null ;
const result2 = orders.find(item => item.order_type == "Wholesale").items
.map(( item) => {
if(item.detail.ID == ID ) {
result = item.quantity;
}
}, 0);
return result ;
}
console.log( "result" ,findMyItem( 13363 ) )
console.log( "result" ,findMyItem( 98223) )
console.log( "result" ,findMyItem( 76884) )
You could use Array.find() on the orders array to find the correct order, searching for the first order that matches both the order_type and has an item matching the desired itemId (using Array.some()).
If this order exists, we can then find the corresponding item quantity using .find() again,
const orders = [ { "order_id": 47445, "order_type": "Wholesale", "items": [ { "id": 9, "department": "Womens", "type": "Dress", "quantity": 4, "detail": { "ID": 13363, "On Sale": 1, } }, { "id": 56, "department": "Womens", "type": "Skirt", "quantity": 12, "detail": { "ID": 76884, "On Sale": 0, } }, { "id": 89, "department": "Mens", "type": "Shirts", "quantity": 20, "detail": { "ID": 98223, "On Sale": 1, } } ] } ]
function findItemQuantity(orders, orderType, itemId) {
// Find the first order with the right order_type and containing the right item id
const order = orders.find(order => order.order_type = orderType && order.items.some(item => item.detail.ID === itemId));
if (!order) {
return null;
}
const item = order.items.find(item => item.detail.ID === itemId);
if (!item) {
return null;
}
return item.quantity;
}
console.log("Quantity found:", findItemQuantity(orders, 'Wholesale', 13363))
console.log("Quantity found:", findItemQuantity(orders, 'Wholesale', 76884))
const result = orders
.filter(order => order.order_type == "Wholesale")
.map(order => order.items.find(item => item.detail.ID == 13363))
.filter(item => item)
.reduce((total, { quantity }) => quantity + total, 0);
const orders = [{
"order_id": 47445,
"order_type": "Wholesale",
"items": [{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
}]
},
{
"order_id": 47445,
"order_type": "Whole",
"items": [{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
}]
}
]
const result = orders.reduce(v => {
return v.items.map(a => {
if (v.order_type == 'Wholesale' && a.detail.ID == 13363) {
return v
}
})
})
console.log(result)
const orders = [{
"order_id": 47445,
"order_type": "Wholesale",
"items": [{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
}]
}];
var result = null;
const result2 = orders.find(item => item.order_type == "Wholesale").items
.map((item) => {
if (item.detail.ID == 98223) {
result = item.quantity;
}
}, 0);
console.log("result", result)

How to compare two objects with lodash and return new object?

Here are two objects I need to compare and return specific values from object1 if found in object2.
object1 = {
"body": {
"items": [
{
"data": {
"name": "Smith",
"status": "Ready",
"userinfo": [
{
"dob": "01/01/2000",
"nickname": "Joe"
}
]
},
"workinfo": {
"company": "mycompany",
"address": "101 Main str."
}
},
{
"data": {
"name": "Luke",
"status": "Ready",
"userinfo": [
{
"dob": "01/01/2001",
"nickname": "LL"
}
]
},
"workinfo": {
"company": "mycompany",
"address": "101 Main str."
}
}
]
}
}
Object2 is even simple one:
object2 = {
"items": [
{
"name": "Smith",
"status": "Ready"
},
{
"name": "Luke",
"status": "Ready"
}
]
}
So if Object1 body.items[x].data.name found in Object2 items.name then finally I need to get new object like this:
object3 = {{name: "Smith", status: "Ready"}, {name: "Luke", status: "Ready"}}
You can use filter and find:
var obj1 = {
"body": {
"items": [{
"data": {
"name": "Smith",
"status": "Ready",
"userinfo": [{
"dob": "01/01/2000",
"nickname": "Joe"
}]
},
"workinfo": {
"company": "mycompany",
"address": "101 Main str."
}
},
{
"data": {
"name": "Luke",
"status": "Ready",
"userinfo": [{
"dob": "01/01/2001",
"nickname": "LL"
}]
},
"workinfo": {
"company": "mycompany",
"address": "101 Main str."
}
}
]
}
}
var obj2 = {
"items": [{
"name": "Smith",
"status": "Ready"
},
{
"name": "Luke",
"status": "Ready"
}
]
}
var output = obj2.items.filter(({name}) => obj1.body.items.find(({data}) => name === data.name))
console.log(output)
Filter will return all the objects that pass the find condition, that is, if the name is found in obj1
You can use _.intersectionWith() to return items from obj2, that their name equals data.name in obj2 items:
const obj1 = {"body":{"items":[{"data":{"name":"Smith","status":"Ready","userinfo":[{"dob":"01/01/2000","nickname":"Joe"}]},"workinfo":{"company":"mycompany","address":"101 Main str."}},{"data":{"name":"Luke","status":"Ready","userinfo":[{"dob":"01/01/2001","nickname":"LL"}]},"workinfo":{"company":"mycompany","address":"101 Main str."}}]}}
const obj2 = {"items":[{"name":"Smith","status":"Ready"},{"name":"Luke","status":"Ready"}]}
const result = _.intersectionWith(obj2.items, obj1.body.items,
(a, b) => _.get(a, 'name') === _.get(b, 'data.name')
)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
With ES6 this is an easy task with Array.filter and Array.some:
const obj1 = {"body":{"items":[{"data":{"name":"Smith","status":"Ready","userinfo":[{"dob":"01/01/2000","nickname":"Joe"}]},"workinfo":{"company":"mycompany","address":"101 Main str."}},{"data":{"name":"Luke","status":"Ready","userinfo":[{"dob":"01/01/2001","nickname":"LL"}]},"workinfo":{"company":"mycompany","address":"101 Main str."}}]}}
const obj2 = {"items":[{"name":"Smith","status":"Ready"},{"name":"Luke","status":"Ready"}]}
const r = obj2.items.filter(x => obj1.body.items.some(y => y.data.name == x.name))
console.log(r)
Since you have the objects in the correct layout in obj2 you can start from there and filter them against obj1.

Fetch the no of of occurence in a array based on other key value

var json = [{
"city": "California",
"name": "Joe",
"age": 17,
"type",:"custom"
}, {
"city": "California",
"name": "Bob",
"age": 17,
"type",:"predefined"
}, {
"city": "California",
"name": "Bob",
"age": 35,
"type",:"custom"
}, {
"city": "Texas",
"name": "Bob",
"age": 35,
"type",:"custom"
}, {
"city": "Florida",
"name": "Bob",
"age": 35,
"type",:"predefined"
}];
I have above array and i have to construct object, based on "type" value i.e "predefined" or "custom" as below
updatedjson = {
"predefined": [{
"name": "California",
"count": 1
}, {
"name": "Florida",
"count": 1
}]
"custom": [{
"name": "California",
"count": 2
}, {
"name": "Texas",
"count": 1
}]
}
Any Approach using javascript or lodash
Using Lodash
var json = [{
"city": "California",
"name": "Joe",
"age": 17,
"type": "custom"
}, {
"city": "California",
"name": "Bob",
"age": 17,
"type": "predefined"
}, {
"city": "California",
"name": "Bob",
"age": 35,
"type": "custom"
}, {
"city": "Texas",
"name": "Bob",
"age": 35,
"type": "custom"
}, {
"city": "Florida",
"name": "Bob",
"age": 35,
"type": "predefined"
}];
// Solution to the problem
var updatedJson = _(json).groupBy("type").value(); // #1
_.forOwn(updatedJson, function(value, key) {
let countByCity = _(value).countBy('city').value(); // #2
let res = [];
_.forOwn(countByCity, function(value, key) {
res.push({ // #3
name: key,
count: value
});
});
updatedJson[key] = res;
});
console.log(updatedJson);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
Explanation
Code first groups by type
Then counts by cities, within the group
Finally pushes the count object into an array, in the expected format
You can use reduce & findIndex
var json = [{
"city": "California",
"name": "Joe",
"age": 17,
"type": "custom"
}, {
"city": "California",
"name": "Bob",
"age": 17,
"type": "predefined"
}, {
"city": "California",
"name": "Bob",
"age": 35,
"type": "custom"
}, {
"city": "Texas",
"name": "Bob",
"age": 35,
"type": "custom"
}, {
"city": "Florida",
"name": "Bob",
"age": 35,
"type": "predefined"
}];
var updatedjson = json.reduce(function(result, item) {
// check if type is present in the object
// if not present then add a key by name custom/predefined
if (!result[item.type]) {
result[item.type] = [];
// add city name and intial count
result[item.type].push({
name: item.city,
count: 1
})
} else {
// now find the index of the object whe name matches with current city
let m = result[item.type].findIndex(function(obj) {
return obj.name === item.city
})
// if no matches then add the new object to either custom/predefined
if (m === -1) {
result[item.type].push({
name: item.city,
count: 1
})
} else {
// if matches then increase the value of count
result[item.type][m].count += 1
}
}
return result;
}, {});
console.log(updatedjson)
You can use array.reduce to create a new object with the aggregated data. Example:
const result = json.reduce((obj, data) => {
// if this is a new type, we must initialize it as an empty array and push the first record.
if(!obj[data.type]) {
obj[data.type] = [];
obj[data.type].push({name: data.city, count: 1});
return obj;
}
// else ... check if the current city is present in that type
const existingRecord = obj[data.type].find(d => d.name === data.city);
if(!existingRecord) {
// if the city is not present in that type, we initialize it with count 1
obj[data.type].push({name: data.city, count: 1});
return obj;
}
// if the city is present, we just update count = count + 1;
existingRecord.count++;
return obj;
}, { })
Now, you probably want to extract some of that logic into separate functions to increase readability. I don't think you need lodash for this but in the case you already have it included in your project then feel free to use it :P

How to parse the following json in javascript (ReactNative) having dynamic key value pair?

I have the following JSON response coming from an API.
{
"status": true,
"cakes": {
"7689": {
"id": 7689,
"flavor": "chocolate",
"cookDetails": {
"id": 101,
"firstName": "Name1",
"lastName": "LastName1"
}
},
"7690": {
"id": 7690,
"flavor": "vanilla",
"cookDetails": {
"id": 102,
"firstName": "Name2",
"lastName": "LastName2"
}
}
}
}
Language I'm using to parse this JSON: Javascript
Framework: ReactNative
How do I parse it (NOTE: I don't know the value of id in cakes until I parse it)?
PS: New to the framework. Big thanks.
I am not sure about that but I think you want to somehow access a cake with id e.x. 7689 without knowing its id value. So you have several ways to deal with it. One of them is to iterate over them using for...in loop:
for(var cakeId in response.cakes){
var cake = response.cakes[cakeId];
console.log(cake);
// Do whatever you want with your cake
}
I am sorry if I misunderstood you. If so, please clarify the question by providing us with some examples of what you would like to achieve.
create a function
function getCake(obj,key){
let cake = obj['cakes'][key];
return cake;
}
call
let cakes = {
"status": true,
"cakes": {
"7689": {
"id": 7689,
"flavor": "chocolate",
"cookDetails": {
"id": 101,
"firstName": "Name1",
"lastName": "LastName1"
}
},
"7690": {
"id": 7690,
"flavor": "vanilla",
"cookDetails": {
"id": 102,
"firstName": "Name2",
"lastName": "LastName2"
}
}
}
}
getCake(cakes,'7689');
Try this out
const cakesObject = {
"status": true,
"cakes": {
"7689": {
"id": 7689,
"flavor": "chocolate",
"cookDetails": {
"id": 101,
"firstName": "Name1",
"lastName": "LastName1"
}
},
"7690": {
"id": 7690,
"flavor": "vanilla",
"cookDetails": {
"id": 102,
"firstName": "Name2",
"lastName": "LastName2"
}
}
}
};
// this is required only if cakesObject is strigified
const { cakes } = JSON.parse(cakesObject);
const cakesArray = [..Object.values(cakes)];
cakesArray.forEach(cake => {
const { id } = cake;
// write further logic
})

formatting data into a new structure 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; }

Categories