I am iterating over a couple of JSON arrays of objects and comparing properties to add a property from one to the other. It is returning an array with all undefined values. I am not sure why, any suggestions?
let urls = [facultyBiosJSON, facultyDirectoryJSON]; async function getJson() { let facultyArray; const [ data1, data2 ] = await Promise.all([ fetch(urls[0]).then(response => response.json()), fetch(urls[1]).then(response => response.json()) ]); facultyArray = data1[0].users.map(user1 => { data2[0].users.map(user2 => { if(user1.name === user2.name){ return {...user1, title: user2.title} } return user2; }); }); random(facultyArray); // pulls 6 random users from the new array
}
Hi @svoltmer1
Without saying a lot, the first cause of returning undefined here is that you are returning nothing !
I leave some comment below check it.
PS: I dind’t respond directly to your code, respond it yourself so you will remember this whenever you got this problems, keep going and keep learning js is colol.
I split it up into a number of functions — a bit cleaner that way.
const getRandomItems = (arr, num = 5) => { const shuffled = [...arr].sort(() => 0.5 - Math.random()); const numToReturn = Math.min(arr.length, num); return shuffled.slice(0, numToReturn);
} // separate function to fetch Json from one file
async function fetchJson(url) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error: ${response.status}`); } return await response.json(); } catch (error) { console.error(error); }
} // separate function to fetch multiple Json files.
async function fetchAll(urls = []) { return await Promise.all(urls.map(fetchJson));
} async function getFacultyUsers(url1, url2) { const [data1, data2] = await fetchAll([url1, url2]) const users1 = data1[0].users; const users2 = data2[0].users; // return all the users return users1.map((user) => { const targetName = user.name; // find user object with same name const foundUser = (users2.find((user) => user.name === targetName)); // if match found return with amended title // or user object as is return (foundUser !== undefined) ? { ...user, title: foundUser.title } : user; })
} // just an example using the above functions
async function doSomethingHere() { const facultyUsers = await getFacultyUsers( 'https://url1here...', 'https://url2here...' ) // Makes more sense to me to get randomUsers // outside of the getFacultyUsers function const randomUsers = getRandomItems(users, 6) ...
}
I don’t know your data, so this is all guess work. Array.find may not be usable.
Thanks, but I’ve tried adding a return statement in front of the first map, but it then returns a copy of the array for all the iterations.
@svoltmer1 It’s difficult to give a proper solution without seeing a sample of the data you are working with.
I have no idea on what data you treat but the answer @rpg_digital give some idea using find may work instead of map in the scopes of the first map
Your right. It is two JSON arrays, one with a “title” property and one with a “bio” property, I need to add the title property to the JSON array of objects with the bio property, based on the users.name property.
So, this is the basic structure. There is a large array that I only need the corresponding titles for faculty in the other array of objects.
[
{"users": [ {"name": "Tim Blackburn", "title": "Assistant Professor of Chemistry", "bio": "Tim is an avid..." }, {"name": "Greg Fortner", "title": "Director of Academic Affairs", "bio": "Greg likes kites..." }, ]
}
]
Sorry so are we talking data a bit like this?
const bios = [ {"users": [ {"name": "Tim Blackburn", "bio": "Tim is an avid..." }, {"name": "Greg Fortner", "bio": "Greg likes kites..." }, {"name": "John Smith", "bio": "John likes to fish..." } ] }
] const titles = [ {"users": [ {"name": "Tim Blackburn", "title": "Assistant Professor of Chemistry", }, {"name": "Greg Fortner", "title": "Director of Academic Affairs", }, {"name": "John Smith", "title": "Headmaster" } ] }
]
Testing with similar code to my previous post
function getFacultyUsers(bios, titles) { const userBios = bios[0].users; const userTitle = titles[0].users; // return all the users return userBios.map((user) => { const targetName = user.name; // find user object with same name const foundUser = (userTitle.find((user) => user.name === targetName)); // if match found return with amended title // or user object as is return (foundUser !== undefined) ? { ...user, title: foundUser.title } : user; })
} console.log(getFacultyUsers(bios, titles));
Outputs
[ {name: 'Tim Blackburn', bio: 'Tim is an avid...', title: 'Assistant Professor of Chemistry'}, {name: 'Greg Fortner', bio: 'Greg likes kites...', title: 'Director of Academic Affairs'}, {name: 'John Smith', bio: 'John likes to fish...', title: 'Headmaster'}
]
Is that what you are after?
If it is, in theory the last two functions I wrote could be amended to
// just deals with the json data now,
// no async fetching. Easier to test this way.
function getFacultyUsers(bios, titles) { const userBios = bios[0].users; const userTitle = titles[0].users; // return all the users return userBios.map((user) => { const targetName = user.name; // find user object with same name const foundUser = (userTitle.find((user) => user.name === targetName)); // if match found return with amended title // or user object as is return (foundUser !== undefined) ? { ...user, title: foundUser.title } : user; })
} // do our fetching here instead
async function doSomethingHere() { const urls = [ 'https://biosUrlhere...', 'https://titlesUrlhere...' ] const [bios, titles] = await fetchAll(urls) const users = getFacultyUsers(bios, titles) const randomUsers = getRandomItems(users, 6) ...
}
Something that crossed my mind last night, what if you have multiple users with the same name? Is there no userId?
Maybe over-engineering here, but I was thinking about how you could use a lookup instead of using Array.find.
I came up with a generic higher-order function to create the lookup.
/** @PARAMS {FUNCTION, ARRAY} @RETURNS {OBJECT} Expects a callback Function and an Array of Objects The callback Function should return a tuple [key, prop]
*/
const createFromPairs = (fn, source = []) => { const target = {}; for (let i = 0, len = source.length; i < len; i++) { // passes in the source item, the index and the source // to a callback function const [key, prop] = fn(source[i], i, source); target[key] = prop; } return target;
}
Usage
Example data:
const bios = [ { users: [ { userId: 1, name: "Tim Blackburn", bio: "Tim is an avid..." }, { userId: 2, name: "Greg Fortner", bio: "Greg likes kites..." }, { userId: 3, name: "John Smith", bio: "John likes to fish..." }, { userId: 4, name: "Sally Brown", bio: "Sally is a martial artist..." } ] }
] const titles = [ { users: [ { userId: 1, name: "Tim Blackburn", title: "Assistant Professor of Chemistry" }, { userId: 2, name: "Greg Fortner", title: "Director of Academic Affairs" }, { userId: 4, name: "Sally Brown", title: "Headmistress" } ] }
]
Create a lookup
const lookup = createFromPairs( // name becomes key, title becomes value (user) => ([user.name, user.title]), // source array titles[0].users
);
Output:
{ "Greg Fortner": "Director of Academic Affairs" "Sally Brown": "Headmistress" "Tim Blackburn": "Assistant Professor of Chemistry"
}
Obviously using the userId’s would make more sense, but keeping inline with the brief.
Merging the props:
With the lookup you can then create your merged objects as follows:
const userBios = bios[0].users userBios.map((user) => { // look up the name in titles return (user.name in lookup) ? { ...user, title: lookup[user.name] } : user;
});
Here is a codepen to demonstrate
There won’t be users with the same name. There is a property named “filename”, which refers to their actual profile page on the website. It is totally unique to the user’s profile page. I guess I should be testing for that instead.
Another thing that I see as an issue. When using the find(user), I needed to exclude users that don’t have a user.image or a user.image.includes(“Faculty_Bio-Photoholder.jpg”), but find doesn’t seem to work with multiple conditions. I’ve tried using filter instead, but it’s returning an empty array even when all the conditions are met. Super confused.
function getFacultyUsers(bios, titles) { const userBios = bios[0].users; const userTitle = titles[0].users; return userBios.map((user) => { const targetName = user.name; const targetImage = user.image; // find user object with same name const foundUser = (userTitle.find((user) => user.name === targetName && targetImage !== undefined)); return (foundUser !== undefined && foundUser.title !== undefined && !user.image.includes("Faculty_Bio-Photoholder.jpg")) ? { ...user, title: foundUser.title } : user; })
}
What am I missing? Thanks for all your help!
Techyrack Website stock market day trading and youtube monetization and adsense Approval
Adsense Arbitrage website traffic Get Adsense Approval Google Adsense Earnings Traffic Arbitrage YouTube Monetization YouTube Monetization, Watchtime and Subscribers Ready Monetized Autoblog
from Web Development – My Blog https://www.techyrack.com/syndication/2022/09/26/array-map-returning-array-of-undefined-values-javascript-sitepoint/
via IFTTT
No comments:
Post a Comment