mapping items and flattening into single array in reactjs - javascript

Currently I have a reactjs function that simply queries a pouchDB document, gets 7 records and then I'm trying to flatten those records in order to store in state. The problem is that, right now when I console.log docCalories I get this:
(7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {caloriesBurned: "5345", createdAt: "2020-03-28T05:15:24.369Z"}
1: {caloriesBurned: "1234", createdAt: "2020-03-28T10:39:16.901Z"}
2: {caloriesBurned: "1122", createdAt: "2020-03-28T10:32:03.100Z"}
3: {caloriesBurned: "1234", createdAt: "2020-03-28T05:16:54.846Z"}
4: {caloriesBurned: "1234", createdAt: "2020-03-28T10:21:31.092Z"}
5: {caloriesBurned: "1234", createdAt: "2020-03-28T05:08:00.791Z"}
6: {caloriesBurned: "1234", createdAt: "2020-03-28T05:07:35.940Z"}
length: 7__proto__: Array(0)
but I want to get something that looks like this:
map: [5345,1234,1122,1234,1234,1234,1234]
So basically one object that contains the 7 numbers from each doc's caloriesBurned value
What am I doing wrong here and how can I properly put these into one array/object?
setMax = () => {
this.state.caloriesDB.db.find({
selector: {
$and: [
{_id: {"$gte": null}},
{caloriesBurned: {$exists: true}},
{createdAt: {$exists: true}}
]
},
fields: ['caloriesBurned', 'createdAt'],
sort: [{'_id':'desc'}],
limit: 7
}).then(result => {
const newDocs = result.docs;
const docCalories = newDocs.map((caloriesBurned) => caloriesBurned)
console.log('this is map');
console.log(docCalories);
}).catch((err) =>{
console.log(err);
});
}

You're returning the entire object in your map function, instead you should only send the caloriesBurned property.
const docCalories = newDocs.map((data) => data.caloriesBurned)
or if you like, we can destructrure data and have
const docCalories = newDocs.map(({caloriesBurned}) => caloriesBurned)

What Dupocas has written in the comments is correct.
newDocs is a list of objects and with this code:
const docCalories = newDocs.map((caloriesBurned) => caloriesBurned)
you will just get another list that is just like newDocs. What you want to return from the map function is a specific key, so try:
const docCalories = newDocs.map(doc => doc.caloriesBurned)

considering docCalories value in m2 by creating map, you can do something like this -
const m2 = new Map(Object.entries([{
0: {
caloriesBurned: "5345",
createdAt: "2020-03-28T05:15:24.369Z"
}
},
{
1: {
caloriesBurned: "1234",
createdAt: "2020-03-28T10:39:16.901Z"
}
},
{
2: {
caloriesBurned: "1122",
createdAt: "2020-03-28T10:32:03.100Z"
}
},
{
3: {
caloriesBurned: "1234",
createdAt: "2020-03-28T05:16:54.846Z"
}
},
{
4: {
caloriesBurned: "1234",
createdAt: "2020-03-28T10:21:31.092Z"
}
},
{
5: {
caloriesBurned: "1234",
createdAt: "2020-03-28T05:08:00.791Z"
}
},
{
6: {
caloriesBurned: "1234",
createdAt: "2020-03-28T05:07:35.940Z"
}
}
]))
var store = [];
Array.from(m2).map(([key, value]) => store.push(value[key].caloriesBurned));
console.log(store);

Related

Javascript extracting values from deeply nested array object structure

I'm trying to pull out specific fields from backend data to prep the body of a table. The data coming in has the structure of:
[
{
_id: "63056cee252b83f4bc8f97e9",
goals: [
{ title: "Cook" },
{ title: "Budget" }
],
visitEnd: "2022-08-18T00:30:00.000Z",
visitStart: "2022-08-17T21:30:00.000Z",
},
{
_id: "63223586798c6b2658a0d576",
goals: [
{ title: "Cook" },
{ title: "Budget" },
{ title: "Clean" }
],
visitEnd: "2022-09-13T00:30:00.000Z",
visitStart: "2022-09-12T22:00:00.000Z"
},
{
_id: "63542ecfca5bd097a0d9acaf",
goals: [
{ title: "Cook" },
{ title: "Clean" }
],
visitEnd: "2022-10-12T19:00:11.000Z",
visitStart: "2022-10-12T17:00:00.000Z",
}]
Since the table headers are by month/year, I'm using lodash to group them by month, which gets me here:
Object { 7: (2) […], 8: (2) […], 9: (2) […] }
​
7: Array [ {…}, {…} ]
​​
0: Object { user: "62410a1dcaac9a3d0528de7a", location: "Firm Office in LA", visitStart: "2022-08-17T21:30:00.000Z", … }
​​
1: Object { user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-08-11T21:00:57.000Z", … }
​​
length: 2
​​
<prototype>: Array []
​
8: Array [ {…}, {…} ]
​​
0: Object { user: "62410a1dcaac9a3d0528de7a", location: "Home", visitStart: "2022-09-12T22:00:00.000Z", … }
​​
1: Object { user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-09-21T21:00:00.000Z", … }
​​
length: 2
​​
<prototype>: Array []
​
9: Array [ {…}, {…} ]
​​
0: Object { user: "62410a1dcaac9a3d0528de7a", location: "Home", visitStart: "2022-10-12T17:00:00.000Z", … }
​​
1: Object { user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-10-21T21:00:00.000Z", … }
​​
length: 2
But now I'm stuck since I want to isolate the fields of the goals array, which is within the objects, within the array of each month, which is contained in an object. I've tried playing around with Object.keys and maps, and then from here: https://dev.to/flexdinesh/accessing-nested-objects-in-javascript--9m4 came across a function to get deeply nested items. But I'm still messing this up, and my head is spinning trying to make sense of it. I looked at lodash's map and property, but was not sure how to implement given the layers of nesting I'm trying to work through on dynamically named arrays within the groupBy object. Heres where I'm at, but I'm getting the error i.map is not a function
const sort = groupBy(visits, ({visitEnd})=> new Date(visitEnd).getMonth());
console.log("sort 1: ", sort)
const stage = Object.keys(sort).map((i) => {
{ i.map((el) => getNestedObject(el, ['goals', 'title'])) }
})
console.log("sort 2: ", stage)
My javascript knowledge is terrible which doesn't help...
The error you're getting, i.map is not a function, means that the variable i is not an array. Based on the data you supplied in your post i is an object.
Iterate the result of the sorted month/year data using Object.entries() versus Object.keys().
To get a list of unique goals per month with output that looks like:
{
7: ["Cook", "Spend", "Clean"],
8: ["Cook", "Budget", "Clean"],
9: ["Cook", "Budget", "Scrub", "Fold", "Rest", "Wash"]
}
const dataSortedByMoYrObj = {
7: [
{
user: "62410a1dcaac9a3d0528de7a", location: "Firm Office in LA", visitStart: "2022-08-17T21:30:00.000Z",
goals: [
{ title: "Cook" },
{ title: "Spend" },
{ title: "Clean" }
]
},
{
user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-08-11T21:00:57.000Z",
goals: [
{ title: "Cook" },
{ title: "Clean" }
]
}
],
8: [
{
user: "62410a1dcaac9a3d0528de7a", location: "Home", visitStart: "2022-09-12T22:00:00.000Z",
goals: [
{ title: "Cook" },
{ title: "Budget" },
{ title: "Clean" }
]
},
{ user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-09-21T21:00:00.000Z" }
],
9: [
{
user: "62410a1dcaac9a3d0528de7a", location: "Home", visitStart: "2022-10-12T17:00:00.000Z",
goals: [
{ title: "Cook" },
{ title: "Budget" },
{ title: "Scrub" }
]
},
{
user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-10-21T21:00:00.000Z",
goals: [
{ title: "Fold" },
{ title: "Rest" },
{ title: "Wash" }
]
}
]
};
// 'const getNestedObject' code sourced from:
// https://dev.to/flexdinesh/accessing-nested-objects-in-javascript--9m4
const getNestedObject = (nestedObj, pathArr) => {
return pathArr.reduce((obj, key) =>
(obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}
const goalsByMonthYearObj = {};
Object.entries(dataSortedByMoYrObj).forEach(([month, users]) => {
// 'month' represents the key.
// 'users' is an array of objects listed for each month.
let goalsByMonth = [];
users.map(user => {
const goalsProp = getNestedObject(user, ['goals']);
// Check if the 'goals' property is a valid.
// If 'goals' property is 'null' or 'undefined',
// '!Array.isArray(null)' returns 'true'.
if (!Array.isArray(goalsProp)) { return; }
// Convert list of goal objects (e.g. '{title: Budget}')
// to an array using 'goalsProp.map()' and then
// concatenate goals array to the existing
// goals-by-month array.
goalsByMonth = goalsByMonth.concat(goalsProp.map(goal => goal.title));
});
// Add array of unique goals for each month
// https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates
goalsByMonthYearObj[month] = [...new Set(goalsByMonth)];
});
console.log(goalsByMonthYearObj);
(Original code that's not as concise as above snippet.)
const goalsByMonthYearObj = {};
// Reference to 'Object.entries()' at:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
for (const [key, value] of Object.entries(dataSortedByMoYrObj)) {
// 'key' represents a month index.
// 'value' contains an array of objects listed for each month index.
//console.log(`${key}: ${value}`);
const goalsByMonth = [];
value.forEach(item => {
// The 'goals' property is only one level deep so
// it's not necessary to use the 'getNestedObject()'
// function.
// For example: const goalsProp = item.goals;
// The function is useful for more deeply
// embedded properties.
const goalsProp = getNestedObject(item, ['goals']);
if (!Array.isArray(goalsProp)) { return; }
goalsProp.forEach(goal => {
if (!goal.title) { return; }
goalsByMonth.push(goal.title);
});
});
// https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates
const uniqueGoals = [...new Set(goalsByMonth)];
goalsByMonthYearObj[key] = uniqueGoals;
}
console.log(goalsByMonthYearObj);

My API is returning undefined instead of response value

I'm consuming an API using Axios in React, but when i come to set the response in a State so I may use the data, it is undefined. The funny thing is, if I put console.log inside Get.js I see the array perfectly. Am I returning the value the wrong way ?
PS: When I use console.log inside the Get.js,inside the 2nd .then, it prints two times the array. Why ?
MainPage.jsx
import { useEffect, useState } from 'react';
import { axiosGet } from '../../services/Get';
import { Header } from '../../components/Header/';
import { Welcome } from '../../components/Welcome/';
export const MainPage = () => {
const [data, setData] = useState([]);
useEffect(() => {
console.log(axiosGet());
setData(axiosGet());
}, []);
return (
<>
<Header />
<Welcome />
{data.length &&
data.map(obj => {
<p key={obj.id}>obj.name</p>;
})}
</>
);
Get.js
import axios from 'axios';
export function axiosGet() {
axios
.get(
`https://api.rawg.io/api/games?key=a6a08e14b07f41d09e846ec3c01e5db0&dates=2019-10-10,2022-03-01&page=2`
)
.then(res => {
return res.data.results;
})
.then(arr => {
return arr;
})
.catch(err => {
console.error('oops! error: ' + err);
});
}
if I change the Get.js code at this piece of code:
.then(res => {
return res.data.results;
})
.then(arr => {
console.log(arr)
return arr;
})
I got this:
Array(20) [ {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, … ]
​
0: Object { slug: "forza-horizon-5", name: "Forza Horizon 5", playtime: 11, … }
​
1: Object { slug: "call-of-duty-modern-warfare", name: "Call of Duty: Modern Warfare (2019)", playtime: 0, … }
​
2: Object { slug: "resident-evil-village", name: "Resident Evil: Village", playtime: 16, … }
​
3: Object { slug: "assassins-creed-valhalla", name: "Assassin's Creed Valhalla", playtime: 0, … }
​
4: Object { slug: "genshin-impact", name: "Genshin Impact", playtime: 0, … }
​
5: Object { slug: "mafia", name: "Mafia: Definitive Edition", playtime: 9, … }
​
6: Object { slug: "superhot-mind-control-delete", name: "SUPERHOT: MIND CONTROL DELETE", playtime: 2, … }
​
7: Object { slug: "valheim", name: "Valheim", playtime: 11, … }
​
8: Object { slug: "it-takes-two-2", name: "It Takes Two", playtime: 11, … }
​
9: Object { slug: "deep-rock-galactic", name: "Deep Rock Galactic", playtime: 6, … }
​
10: Object { slug: "risk-of-rain-2", name: "Risk of Rain 2", playtime: 7, … }
​
11: Object { slug: "tell-me-why", name: "Tell Me Why", playtime: 2, … }
​
12: Object { slug: "factorio", name: "Factorio", playtime: 17, … }
​
13: Object { slug: "ghostrunner", name: "Ghostrunner", playtime: 4, … }
​
14: Object { slug: "marvels-avengers", name: "Marvel’s Avengers", playtime: 14, … }
​
15: Object { slug: "mafia-iii-definitive-edition", name: "Mafia III: Definitive Edition", playtime: 0, … }
​
16: Object { slug: "guardians-of-the-galaxy", name: "Marvel's Guardians of the Galaxy", playtime: 8, … }
​
17: Object { slug: "need-for-speed-heat", name: "Need for Speed Heat", playtime: 3, … }
​
18: Object { slug: "marvels-spider-man-miles-morales", name: "Marvel's Spider-Man: Miles Morales", playtime: 0, … }
​
19: Object { slug: "streets-of-rage-4", name: "Streets of Rage 4", playtime: 4, … }
​
length: 20
​
<prototype>: Array []
Get.js:12:15
The function axios.get() returns a Promise of the data you want.
You need to modify your code to return this promise to the calling function:
export function axiosGet() {
return axios
.get(
`https://api.rawg.io/api/games?key=a6a08e14b07f41d09e846ec3c01e5db0&dates=2019-10-10,2022-03-01&page=2`
)
And then you need to await for an answer (to go from a Promise to the data):
useEffect(async () => {
console.log(await axiosGet());
setData(await axiosGet());
}, []);
The problem is that axiosGet doesn't actually return anything.
You can't though get it to directly return the API data, since that is only retrieved asynchronously. See this question for lots of discussion as to how to get the response from asynchronous requests and use it in your code.
In your case probably the easiest solution is to have axiosGet return the promise that axios.get (and your subsequent .then calls from it) gives you, and then await that in your useEffect so that you can set the state in your component to it.
So I would make the following changes:
First add the return statement to axiosGet:
export function axiosGet() {
return axios
.get(
`https://api.rawg.io/api/games?key=a6a08e14b07f41d09e846ec3c01e5db0&dates=2019-10-10,2022-03-01&page=2`
)
.then(res => {
return res.data.results;
})
.then(arr => {
return arr;
})
.catch(err => {
console.error('oops! error: ' + err);
});
}
and adjust the useEffect in your component as follows:
useEffect(async () => {
const apiData = await axiosGet();
setData(apiData);
}, []);

ReactJS Convert my strange array to an object to add it to a list

I have the following array:
[{…}]
0: {id: 2, createdAt: "2021-06-11T10:13:46.814Z", exchangedAt: "2021-06-11T08:04:11.415Z", imageUrl: "url", user: "user", …}
1: ....
2: ....
3: ....
....
length: 5
__proto__: Array(0)
I want to convert it to an object and I found this code, but all I receive is the 0:
Object.keys(fetchedData.data).map(key => console.log(key))
How to access and convert my 5 array values?
So I've iterated across your array and used the 'id' field as a key. The key for each object needs to be unique, so this assumes your ID is unique...
const fetchedData = [
{id: 1, createdAt: "2021-06-11T10:13:46.814Z", exchangedAt: "2021-06-11T08:04:11.415Z", imageUrl: "url", user: "user"},
{id: 2, createdAt: "2021-06-11T10:13:46.814Z", exchangedAt: "2021-06-11T08:04:11.415Z", imageUrl: "url", user: "user"},
{id: 3, createdAt: "2021-06-11T10:13:46.814Z", exchangedAt: "2021-06-11T08:04:11.415Z", imageUrl: "url", user: "user"}
]
obj = {}
fetchedData.forEach(x => {
tempX = {...x}
delete tempX["id"]
obj[x.id] = tempX
})
console.log('Converted object', obj)
//Using your method, just to log the values without converting it into an object, you could do...
fetchedData.forEach(el => console.log("Individual Element", el))
...so when you use Object.keys() you are iterating across the keys of an object, but as this is an array of objects, the keys are just the indexes of the array. .forEach iterates across the array and gives you each element to work with.
You've used .map() in your code, which also iterates through an array, but returns a new array, so you could change each element. .forEach just iterates and doesn't return, so you're better off using this for logging to the console.
a = [
{
"id":1,
"createdAt":"2021-06-11T10:13:46.814Z",
"exchangedAt":"2021-06-11T08:04:11.415Z",
"imageUrl":"url",
"user":"user"
},
{
"id":2,
"createdAt":"2021-06-11T10:13:46.814Z",
"exchangedAt":"2021-06-11T08:04:11.415Z",
"imageUrl":"url",
"user":"user"
},
{
"id":3,
"createdAt":"2021-06-11T10:13:46.814Z",
"exchangedAt":"2021-06-11T08:04:11.415Z",
"imageUrl":"url",
"user":"user"
},
{
"id":2,
"createdAt":"2021-06-11T10:13:46.814Z",
"exchangedAt":"2021-06-11T08:04:11.415Z",
"imageUrl":"url",
"user":"user"
},
{
"id":4,
"createdAt":"2021-06-11T10:13:46.814Z",
"exchangedAt":"2021-06-11T08:04:11.415Z",
"imageUrl":"url",
"user":"user"
}
]
(5) [{…}, {…}, {…}, {…}, {…}]
Object.keys(a).map(key => console.log(key))
VM532:1 0
VM532:1 1
VM532:1 2
VM532:1 3
VM532:1 4
It is accessing to 5 values.

TypeError: Cannot read property 'map' of undefined but state has been stored

I am trying to get a specific team data from the database and store it in a state. But when I map an array inside that data it returns an error. When I console log my state it returns the data below
createdAt: "2021-03-19T13:36:22.868Z"
gameEvent: "basketball"
players: Array(5)
0: {_id: "605ea59c5cdf492b48987107", name: "Jerry Ale", jerseyNumber: "12"}
1: {_id: "605ea59c5cdf492b48987108", name: "Judel Agur", jerseyNumber: "14"}
2: {_id: "605ea59c5cdf492b48987109", name: "qwe", jerseyNumber: "12"}
3: {_id: "605ea59c5cdf492b4898710a", name: "qwe", jerseyNumber: "12"}
4: {_id: "605ea59c5cdf492b4898710b", name: "qwe", jerseyNumber: "12"}
length: 5
__proto__: Array(0)
teamName: "Balilihan"
updatedAt: "2021-03-27T03:25:16.148Z"
__v: 0
_id: "6054a8d63fec5c24389624ac"
I have an useEffect to gather this;
useEffect(() => {
const getTeam = async () => {
try {
const { data } = await fetchContext.authAxios.get('get-all-teams');
setIsLoaded(true);
if (isLoaded === true) {
setCurrentTeam(data.find((team) => team._id === row._id));
}
} catch (err) {
console.log(err);
}
};
getTeam();
}, [fetchContext, row, isLoaded]);
and I map the players array in a new variable because I want a controlled inputs for my form because I am updating the data. I am using Formik by the way
let playersOfTeam = currentTeam.players.map((player, index) => [
{
name: player.name,
jerseyNumber: player.jerseyNumber,
},
]);
But when I just get a specific value like the teamName it returns the teamName and when I console log currentTeam.players it returns what I expected to get. I am confused why I get this kind of error
Your data is undefined when the component is first mounted. This is because useEffect runs after render.
So adding a null check is the solution. Personally I prefer optional chaining. Simply change to:
let playersOfTeam = currentTeam?.players?.map((player, index) => [
{
name: player.name,
jerseyNumber: player.jerseyNumber,
},
]);

Combining two objects into one object and sorting by timestamp

In Laravel, I have used this approach to combine to collections together and returning as one collection.
$collection = $messages->merge($texts)->sortByDesc('created_at')
If I dd($colection), it shows Collection object all combined and sorted together.
Then I tried to send it to vue via ajax, however, the data is separated again. So my object looks like this:
item: {
messages: [
0: { ... }
1: { ... }
2: { ... }
3: { ... }
],
texts: [
0: { ... }
1: { ... }
]
}
this is because return response()->json('item' => '$collection') separates them as messages and texts again.
I tried combining them like this, but it overwritten the values (I assume because ids are same).
vm item = this;
// in response of ajax get,
.then(function(response) {
var item = response.data.item;
Object.assign(vm.item.messages, vm.item.texts);
});
What is the right way to combine texts into messages and sorting them by timestamps? They all have created_at in the first level of objects like this:
messages: [
0: { created_at: ... }
],
texts: [
0: { created_at: ... }
]
Update: After icepickle's answer, with concat, I was able to combine them in messages array. Now, I have an issue for created_at values as they are converted to strings. Here are some test data. This is what I got after ordering:
messages: [
0: {
msg: 'hello',
created_at: "2017-10-12 00:48:59"
},
1: {
msg: 'mellow',
created_at: "2017-10-11 16:05:01"
},
2: {
msg: 'meow',
created_at: "2017-10-11 15:07:06"
},
4: {
msg: 'test'
created_at: "2017-10-11 17:13:24"
}
5: {
msg: 'latest'
created_at: "2017-10-12 00:49:17"
}
],
Wouldn't it be enough to concat the arrays, and then sort?
A bit like
let result = ([]).concat(item.messages, item.texts);
or in es6
let result = [...item.messages, ...item.texts]
and then calling sort on the result
// in place sort, result will be sorted, and return the sorted array
result.sort((a, b) => a.created_at - b.created_at);
const items = {
messages: [
{
msg: 'hello',
created_at: "2017-10-12 00:48:59"
},
{
msg: 'mellow',
created_at: "2017-10-11 16:05:01"
},
{
msg: 'meow',
created_at: "2017-10-11 15:07:06"
}
],
texts: [
{
msg: 'test',
created_at: "2017-10-11 17:13:24"
},
{
msg: 'latest',
created_at: "2017-10-12 00:49:17"
}
]
};
let result = [...items.messages, ...items.texts].sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
console.log( result );

Categories

Resources