Why is my object in React showing an undefined Object value? - javascript

Here is my React component:
const ChartItem = ({ id, apiUrl }) => {
const [nivoChartData, setNivoChartData] = useState([]);
//
//declare the API call
const apiCallAndConversionForNivoFormat = useCallback(async () => {
try {
const response = await axios.get(apiUrl);
console.log("response: ");
console.log(response);
//converting api response into the format needed by nivo charts
const dataConvertedForNivo = [
{
id: response.data.symbol,
color: "hsl(90, 70%, 50%)",
data: response.data.historical.forEach((key) => {
key["x"] = key["date"];
key["y"] = key["close"];
delete key["date"];
delete key["close"];
}),
},
];
console.log("dataConvertedForNivo: ");
console.log(dataConvertedForNivo);
setNivoChartData(dataConvertedForNivo);
} catch (e) {
console.error(e);
}
}, [setNivoChartData, apiUrl]);
useEffect(() => {
apiCallAndConversionForNivoFormat();
}, [apiCallAndConversionForNivoFormat]);
return (
<div className="chart-item">
<NivoLineChart key={id} nivoData={nivoChartData} />
</div>
);
};
The logs:
The original API response format before modifying:
{
"symbol": "AAPL",
"historical": [
{
"date": "2021-02-24",
"close": 125.349998
},
{
"date": "2021-02-23",
"close": 125.860001
},
{
"date": "2021-02-22",
"close": 126
},
]
}
^ I believe the response log is now showing "x" and "y" instead of "date" and "close" due to memoization.
nivo chart example format that I need to convert to:
[
{
"id": "AAPL",
"color": "hsl(90, 70%, 50%)",
"data": [
{
"x": "2021-02-24",
"y": 125.349998
},
{
"x": "2021-02-23",
"y": 125.860001
},
{
"x": "2021-02-22",
"y": 126
},
]
}
]
Can anyone understand why the dataConvertedForNivo.data is undefined? And is there any better way to do this response conversion?

You need to replace forEach with map.
const dataConvertedForNivo = [
{
id: response.data.symbol,
color: "hsl(90, 70%, 50%)",
data: response.data.historical.map(key => {
key["x"] = key["date"];
key["y"] = key["close"];
delete key["date"];
delete key["close"];
return key;
}),
},
];

Related

Replace path name to get value using received JSON response key javascript

Given json response below.
{
"status": "success",
"data": {
"cheapest": {
"data": [
{
"logistic_id": 1,
"rate_id": 21
}
]
},
"reguler": {
"data":[
{
"logistic_id": 5,
"rate_id": 74
}
]
},
"ranked": {
"data": []
}
}
}
to get logistic_id value and store to logisticIdValue, I use path:
set("logisticIdValue", x.data.reguler.data[0].logistic_id)
I want to get logistic_id value from response using iteration so i don't have to write const cheapest, reguler and ranked to iterate. It might involve key syntax, something like this but i don't know whats the proper syntax to do this
set("logisticIdValue", x.data.key[1].data[0].logistic_id)
let data = {
"status": "success",
"data": {
"cheapest": {
"data": [{
"logistic_id": 1,
"rate_id": 21
}]
},
"reguler": {
"data": [{
"logistic_id": 5,
"rate_id": 74
}]
},
"ranked": {
"data": []
}
}
};
for (const [key, value] of Object.entries(data)) {
if (key === 'data') {
for (const [key1, value1] of Object.entries(value)) {
for (const [key2, value2] of Object.entries(value1)) {
value2 && value2.map((e, i, arr) => {
console.log('logistic_id:', e.logistic_id);
})
}
}
}
}
In case you need to get array of logistic_id values for all types (cheapest,reguler, ..)
so you can use reduce function to iterate on Object.Keys and accumulate it into array as the following:
const data = {
"status": "success",
"data": {
"cheapest": {
"data": [
{
"logistic_id": 1,
"rate_id": 21
}
]
},
"reguler": {
"data": [
{
"logistic_id": 5,
"rate_id": 74
}
]
},
"ranked": {
"data": []
}
}
};
const logisticIdValues = Object.keys(data.data).reduce((result, key) => {
if (data.data[key].data.length > 0) {
result.push(data.data[key].data[0].logistic_id);
}
return result;
}, []);
console.log(logisticIdValues)
but if you need to get it attached to its type so you can accumulated it in hash instead of array as the following:
const data = {
"status": "success",
"data": {
"cheapest": {
"data": [
{
"logistic_id": 1,
"rate_id": 21
}
]
},
"reguler": {
"data": [
{
"logistic_id": 5,
"rate_id": 74
}
]
},
"ranked": {
"data": []
}
}
};
const logisticIdValuesObj = Object.keys(data.data).reduce((result, key) => {
if (data.data[key].data.length > 0) {
result[key] = data.data[key].data[0].logistic_id;
}
return result;
}, {});
console.log(logisticIdValuesObj)

How I loop the array of index id and loop one by one in communes and category and location?

Here I am working on nodejs typescript API. I am getting the data array of object using map loop. I am getting the "communes" "category" and "location" data from the another API function using issuerId means ID. I am not getting the "communes" "category" and "location". I attached here my code below.
Object.values(premiumValue).map(async(x:any,index:any)=>{
var issuerId = await Object.values(premiumValue)[index].issuer_id
var Communes = await employerDetail.getSingleProfileType(issuerId, 'Communes')
var category = await employerDetail.getSingleProfileType(issuerId, 'company_type')
var location = await employerDetail.getSingleProfileType(issuerId, 'location')
Object.assign(values[issuerId], { Communes }, { category }, { location })
})
return Object.values(values)
I am getting this kind of data only
[
{
"issuer_id": 64,
"company_name": "Gastro Südtirol",
"Total_Job": 2
},
{
"issuer_id": 70,
"company_youtube": "https://www.youtube.com/channel/UCB2bOahchY6Hsc_WXnQ-NCw",
"company_name": "Auto Hofer",
"Total_Job": 2
},
{
"issuer_id": 72,
"company_name": "Assimeran GmbH",
"Total_Job": 2
}
]
I need this kind of data
[
{
"issuer_id": 64,
"company_name": "Gastro Südtirol",
"Total_Job": 2,
"Communes": [],
"category": [],
"location": [
{
"id": 907,
"location": "brixen"
}
]
},
{
"issuer_id": 70,
"company_youtube": "https://www.youtube.com/channel/UCB2bOahchY6Hsc_WXnQ-NCw",
"company_name": "Auto Hofer",
"Total_Job": 2,
"Communes": [],
"category": [],
"location": [
{
"id": 907,
"location": "brixen"
}
]
},
{
"issuer_id": 72,
"company_name": "Assimeran GmbH",
"Total_Job": 2,
"Communes": [],
"category": [],
"location": [
{
"id": 907,
"location": "brixen"
}
]
}
]
But I am getting data without communes, category, and location". Is there any async/await issue here? How I loop the communes, category, and location data using issuerId?
Without knowing the shape of the API data and whatever values is, here's a guess as to how you could use async/await to pull the data in and format it like you're trying to do. I don't see the need for the async map() function; you could instead use a traditional for loop or for...of and wrap everything in an async function:
/***** IGNORE ALL OF THIS, JUST SETUP CODE ****/
const api = [
{
issuer_id: 64,
Communes: [],
company_type: [],
location: [
{
id: 907,
location: "brixen",
},
],
},
{
issuer_id: 70,
Communes: [],
company_type: [],
location: [
{
id: 907,
location: "brixen",
},
],
},
{
issuer_id: 72,
Total_Job: 2,
Communes: [],
company_type: [],
location: [
{
id: 907,
location: "brixen",
},
],
},
];
const values = {
64: {
issuer_id: 64,
company_name: "Gastro Südtirol",
Total_Job: 2,
},
70: {
issuer_id: 70,
company_youtube: "https://www.youtube.com/channel/UCB2bOahchY6Hsc_WXnQ-NCw",
company_name: "Auto Hofer",
Total_Job: 2,
},
72: {
issuer_id: 72,
company_name: "Assimeran GmbH",
Total_Job: 2,
},
};
/*
* Ignore this, it just makes the async stuff actually mimic an API call
*/
function sleep() {
return new Promise((resolve, reject) => {
const time = Math.random() * 500;
setTimeout(() => resolve(time), time);
});
}
const employerDetail = {
getSingleProfileType: async function (issuerId, key) {
await sleep();
return new Promise((resolve, reject) => {
const foundIndex = api.findIndex((el) => el.issuer_id == issuerId);
if (foundIndex === -1) {
reject(`No data in API for issuerId: ${issuerId}`);
} else {
resolve(api[foundIndex][key]);
}
});
},
};
/**** THIS IS WHERE YOU WOULD START USING THINGS ***/
async function getAPIData() {
const apiData = [];
// I'm just looping through the IDs I see in your output
for (const issuerId of [64, 70, 72]) {
const Communes = await employerDetail.getSingleProfileType(issuerId, "Communes");
const category = await employerDetail.getSingleProfileType(issuerId, "company_type");
const location = await employerDetail.getSingleProfileType(issuerId, "location");
apiData.push(Object.assign(values[issuerId], { Communes, category, location }));
}
return apiData;
}
async function main() {
const apiData = await getAPIData();
console.log(JSON.stringify(apiData, null, 2));
}
main();

Remove a sub level of an array

I get a list of items with add-ons from the server, but when I try to delete an add-on from this list I can't. I noticed that when I try to access the property grupoAdicionais.produto.codigo, it does not exist because it has a sublevel coming from the API, how do I remove this to have access to my product.codigo?
Array received from API:
"grupoAdicionais":[
{"produto": {"codigo":21, "descricao":"Bacon"}, "item":148657, "quantidade":1, "total":5},
{"produto": {"codigo":13193, "descricao":"Queijo"}, "item":148657, "quantidade":1, "total":1}
]
My code in the reducer to return the list without the extra:
REMOVER_ADICIONAL: (state, action) => {
let itemRemover = action.item;
let listaReducer = state.lstItensRestauranteQRcode;
const itemRemovido = listaReducer.filter((item) => {
return item.grupoAdicionais.produto.codigo != itemRemover.produto.codigo;
});
state.lstItensRestauranteQRcode = itemRemovido;
},
If all you want to do is get a list of the codes:
const response = {"grupoAdicionais": [{
"produto": {
"codigo": 21,
"descricao": "Bacon"
},
"item": 148657,
"quantidade": 1,
"total": 5
}, {
"produto": {
"codigo": 13193,
"descricao": "Queijo"
},
"item": 148657,
"quantidade": 1,
"total": 1
}]}
const codigos = response.grupoAdicionais.map(grupo => grupo.produto.codigo)
console.log(codigos)
// =>
[ 21, 13193 ]
I'm not totally sure, but it seems like maybe you want to remove a group by its code.
const removeByCode = (code) => response.grupoAdicionais.filter((group) => group.produto.codigo !== code)
const newGroups = removeByCode(21)
console.log(newGroups)
// =>
[
{
produto: { codigo: 13193, descricao: 'Queijo' },
item: 148657,
quantidade: 1,
total: 1
}
]
var response = {"grupoAdicionais": [{
"produto": {
"codigo": 21,
"descricao": "Bacon"
},
"item": 148657,
"quantidade": 1,
"total": 5
}, {
"produto": {
"codigo": 13193,
"descricao": "Queijo"
},
"item": 148657,
"quantidade": 1,
"total": 1
}]}
console.dir(response.grupoAdicionais[0].produto.codigo)
grupoAdicionais is an array here, you have to access it like this:
console.dir(response.grupoAdicionais[0].produto.codigo)

Skip JSON.map() for the subsequent elements

DEMO
(Please check the browser console for output)
I have a JSON customerItemResponse in a format
{
"totalResults": someNumber,
"results": [
{
"totalItem": 406,
"customerId": "10000"
},
{
"totalItem": 468,
"customerId": "10001"
},
{
"totalItem": 20,
"customerId": "10002"
},
...
Then I have another JSON customerInfo:
{
"totalResults": someNumber,
"results": [
{
"customerId": "10000",
"region": "4",
"area": "42",
},
{
"customerId": "10001",
"region": "4",
"area": "43",
},
{
"customerId": "10002",
"region": "5",
"area": "52",
},
Now I have to create a JSON in a format
[
{
region:'4'
regionDetails:[
{
area:'42'
customerDetails:[
{
customerId:'10000'
totalItem:406
},
{
customerId:'10005'
totalItem:301
},
]
},
{
area:'11'
customerDetails:[
{
customerId:'10010'
totalItem:11
},
{
customerId:'10021'
totalItem:105
},
]
},
]
},
{
region:'5'
regionDetails:[
{
area:'52'
customerDetails:[
{
customerId:'10002'
totalItem:52
},
{
customerId:'10027'
totalItem:310
},
]
},
{
area:'41'
customerDetails:[
{
customerId:'10017'
totalItem:109
},
{
customerId:'10041'
totalItem:450
},
]
},
]
}
]
This is the logic I have written:
customerData=<CustomerDataInterface[]>[]
mapJson() {
this.customerItemResponse.map((res, index) => {
this.customerInfo.find((obj) => {
if (obj.customerId == res.customerId) {
this.customerData.length
? this.customerData.map((data, index1) => {
if (data.region == obj.region) {
data.regionDetails.length
? data.regionDetails.map((regDetails, index2) => {
if (regDetails.area == obj.area) {
regDetails.dealerDetails.push({
customerId: obj.customerId,
totalItem: res.totalItem,
});
return;
}
if (index2 == data.regionDetails.length - 1) {
data.regionDetails.push({ area: obj.area, dealerDetails: [] });
}
})
: data.regionDetails.push({ area: obj.area, dealerDetails: [] });
return;
}
if (index1 == this.customerData.length - 1) {
this.customerData.push({ region: obj.region, regionDetails: [] });
}
})
: this.customerData.push({ region: obj.region, regionDetails: [] });
}
});
});
console.log(this.customerData);
}
Now the output of the console has several region repeated. And suppose if I have 6 unique region but the this.customerData.length is 31.
I think return; is not working as expected. And is not skipping the subsequent element.
here is an efficient way to resolving the issue using js Maps. We can build maps with info about corresponding region and then areas. and after the data is built into maps - convert it back to simple js structures, such as object and arrays
mapJson() {
const customerToTotalMap = new Map(this.customerItemResponse.map(({customerId, totalItem}) => [customerId, totalItem]));
const regionsMap = new Map();
for(let {customerId, region, area} of this.customerInfo) {
let regionAreas;
if(regionsMap.has(region)) {
regionAreas = regionsMap.get(region);
} else {
regionAreas = new Map();
regionsMap.set(region, regionAreas);
}
let areaInfo;
if(regionAreas.has(area)) {
areaInfo = regionAreas.get(area);
} else {
areaInfo = [];
regionAreas.set(area, areaInfo);
}
areaInfo.push({customerId, totalItem: customerToTotalMap.get(customerId)});
}
this.customerData = [...regionsMap.entries()].map(([region, areas]) => ({
region,
regionDetails: [...areas.entries()].map(([area, customerDetails]) => ({
area,
customerDetails
}))
}))
console.log(this.customerData);
}
This is similar to #Andrei's answer. It creates an object literal as mapper. Also, it uses mapping between the region and area when they are created. So, finally you can just get the values of the regionMapper object without going through the mapper objects again
const customerItemResponse=[{customerId:10000,totalItem:77},{customerId:10001,totalItem:37},{customerId:10002,totalItem:295},{customerId:10003,totalItem:458},{customerId:10004,totalItem:248},{customerId:10005,totalItem:35},{customerId:10006,totalItem:280},{customerId:10007,totalItem:147},{customerId:10008,totalItem:439},{customerId:10009,totalItem:401},{customerId:10010,totalItem:489},{customerId:10011,totalItem:414},{customerId:10012,totalItem:287},{customerId:10013,totalItem:391},{customerId:10014,totalItem:125},{customerId:10015,totalItem:207},{customerId:10016,totalItem:197},{customerId:10017,totalItem:151},{customerId:10018,totalItem:225},{customerId:10019,totalItem:333},{customerId:10020,totalItem:361},{customerId:10021,totalItem:225},{customerId:10022,totalItem:242},{customerId:10023,totalItem:150},{customerId:10024,totalItem:52},{customerId:10025,totalItem:475},{customerId:10026,totalItem:494},{customerId:10027,totalItem:30},{customerId:10028,totalItem:189},{customerId:10029,totalItem:112},{customerId:10030,totalItem:482},{customerId:10031,totalItem:283},{customerId:10032,totalItem:159},{customerId:10033,totalItem:440},{customerId:10034,totalItem:461},{customerId:10035,totalItem:76},{customerId:10036,totalItem:84},{customerId:10037,totalItem:392},{customerId:10038,totalItem:296},{customerId:10039,totalItem:293},{customerId:10040,totalItem:135},{customerId:10041,totalItem:348},{customerId:10042,totalItem:338},{customerId:10043,totalItem:444},{customerId:10044,totalItem:15},{customerId:10045,totalItem:32},{customerId:10046,totalItem:67},{customerId:10047,totalItem:277},{customerId:10048,totalItem:65},{customerId:10049,totalItem:95},{customerId:10050,totalItem:290}],
customerInfo=[{customerId:10000,region:"3",area:"32"},{customerId:10001,region:"2",area:"22"},{customerId:10002,region:"2",area:"25"},{customerId:10003,region:"3",area:"31"},{customerId:10004,region:"2",area:"25"},{customerId:10005,region:"1",area:"11"},{customerId:10006,region:"1",area:"14"},{customerId:10007,region:"5",area:"55"},{customerId:10008,region:"5",area:"51"},{customerId:10009,region:"4",area:"45"},{customerId:10010,region:"1",area:"14"},{customerId:10011,region:"1",area:"12"},{customerId:10012,region:"3",area:"33"},{customerId:10013,region:"2",area:"25"},{customerId:10014,region:"4",area:"41"},{customerId:10015,region:"3",area:"32"},{customerId:10016,region:"5",area:"55"},{customerId:10017,region:"2",area:"23"},{customerId:10018,region:"3",area:"33"},{customerId:10019,region:"5",area:"51"},{customerId:10020,region:"4",area:"42"},{customerId:10021,region:"1",area:"12"},{customerId:10022,region:"1",area:"14"},{customerId:10023,region:"1",area:"14"},{customerId:10024,region:"1",area:"13"},{customerId:10025,region:"4",area:"45"},{customerId:10026,region:"3",area:"34"},{customerId:10027,region:"2",area:"24"},{customerId:10028,region:"4",area:"45"},{customerId:10029,region:"2",area:"22"},{customerId:10030,region:"2",area:"22"},{customerId:10031,region:"2",area:"21"},{customerId:10032,region:"3",area:"33"},{customerId:10033,region:"1",area:"11"},{customerId:10034,region:"3",area:"33"},{customerId:10035,region:"3",area:"32"},{customerId:10036,region:"2",area:"22"},{customerId:10037,region:"4",area:"41"},{customerId:10038,region:"3",area:"31"},{customerId:10039,region:"5",area:"51"},{customerId:10040,region:"2",area:"23"},{customerId:10041,region:"4",area:"45"},{customerId:10042,region:"1",area:"14"},{customerId:10043,region:"5",area:"54"},{customerId:10044,region:"3",area:"34"},{customerId:10045,region:"5",area:"51"},{customerId:10046,region:"4",area:"42"},{customerId:10047,region:"5",area:"53"},{customerId:10048,region:"1",area:"11"},{customerId:10049,region:"3",area:"35"},{customerId:10050,region:"5",area:"51"}];
const customerItemMapper = {}
for (const c of customerItemResponse)
customerItemMapper[c.customerId] = c.totalItem
const regionMapper = {},
areaMapper = {};
for (const { customerId, region, area } of customerInfo) {
let regionKey = `Region_${region}`,
areaKey = `Area_${area}`,
totalItem = customerItemMapper[customerId];
if (!(regionKey in regionMapper))
regionMapper[regionKey] = { region, regionDetails: [] }
if (!(areaKey in areaMapper)) {
const o = { area, customerDetails: [] }
areaMapper[areaKey] = o;
regionMapper[regionKey].regionDetails.push(o) // area-region relation
}
areaMapper[areaKey].customerDetails.push({ customerId, totalItem })
}
console.log(Object.values(regionMapper))

Javascript Object array get last array

I have a json object array I have two functions. One to get the last message and the other to get. I need to keep the outer format the same but only return the one message.
I am getting the Json from the Telegram api and I have a Node Express script to return the reformatted Json
Here is the full Json:
{
"ok": true,
"result": [
{
"update_id": 650787950,
"channel_post": {
"message_id": 258,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256395,
"text": "test messge"
}
},
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
I have a function to store the object after an api call to Telegram:
storeUpdates(data){
this.messageData = data;
}
For the function to get the last message:
getlastMessage() {
return
}
I am trying to return the Json:
{
"ok": true,
"result": [
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
And for the function to get a specific update_id
getNextMessage(update_id) {
return
}
Again I am trying to get this format of a single message matching the passed in update_id
{
"ok": true,
"result": [
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
I am a little confused with the layers of object and arrays mixed.
Does this work?
const messages = {
ok: true,
result: [{
update_id: 650787950,
channel_post: {
message_id: 258,
chat: {
id: -1001497153100,
title: 'TestBot',
type: 'channel',
},
date: 1592256395,
text: 'test messge',
},
},
{
update_id: 650787951,
channel_post: {
message_id: 259,
chat: {
id: -1001497153100,
title: 'TestBot',
type: 'channel',
},
date: 1592256604,
text: 'next',
},
},
],
};
const getLastMessage = (messages) => {
final = {
ok: true,
result: [],
};
final.result.push(messages.result[messages.result.length - 1]);
return final;
};
const getNextMessage = (update_id, messages) => {
final = {
ok: true
};
final.result = messages.result.filter((msg) => {
return msg.update_id === update_id;
});
return final;
};
console.log(getLastMessage(messages));
console.log(getNextMessage(650787950, messages));
You get the last message by returning the last element in the array, by getting the length of the array and -1
I used Array.prototype.filter() to find the correct object.
To get the last result you would need to go to results and return the last index:
function getlastMessage(resultObject) {
return {
ok: resultObject.ok
result: [resultObject.result[resultObject.result.length - 1]]
}
}
To get the message by update_id:
getNextMessage(update_id) {
return {
ok: resultObject.ok
result: [resultObject.result.find(message => message.update_id === update_id)]
}
}
Something along these lines
Using destructuring you can make your code a little bit more compact:
const someObject = JSON.parse(`{
"ok": true,
"result": [
{
"update_id": 650787950,
"channel_post": {
"message_id": 258,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256395,
"text": "test messge"
}
},
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}`)
const getNextMessage = (update_id) => {
return {
...someObject,
result: someObject.result.find(message => message.update_id === update_id)
}
}
const getLastMessage = () => {
const arrayLength = someObject.result.length;
return {
...someObject,
result: someObject.result[arrayLength - 1]
}
}
console.log(getNextMessage(650787950))
console.log(getLastMessage())
If you want to keep the result type as an array you can use filter instead of find and surround the last element of result array with square brackets, like this:
const getNextMessage = (update_id) => {
return {
...someObject,
result: someObject.result.filter(message => message.update_id === update_id)
}
}
const getLastMessage = () => {
const arrayLength = someObject.result.length;
return {
...someObject,
result: [someObject.result[arrayLength - 1]]
}
}

Categories

Resources