json API response code using flatmap not working javascript - javascript

Problem
I’m trying to return only the objects that don’t contain any of the names on the filteredEmployers list, against the employer attribute, from an API I'm retrieving the data from.
What I've tried
I have an alternative piece of code that seems to work fine when I don’t connect to the API (i.e. reading from hardcoded data), but when I connect to the API, even though I get the following response (when immediately logged after retrieval), the code then doesn’t execute…
{
"Pagination": {
"NumberOfPeople": 185,
"PageSize": 200,
"PageNumber": 1,
"NumberOfPages": 1
},
"People": [
{
"name": "TJ",
"job": "Software Engineer",
"organization": {
"company": {
"employer": "amazon",
"department": "IT"
}
},
"location": {
"city": "Boston",
"state": "Massachusetts"
}
},
{
"name": "Dominique",
"job": "CEO",
"organization": {
"company": {
"employer": "IBM",
"department": "IT"
}
},
"city": "Seattle",
"state": "Washington"
},
{
"name": "Enrique",
"job": "Engineer",
"organization": {
"company": {
"employer": "Bellkrieg Megasystems",
"department": "Construction"
}
},
"location": {
"address": {
"state": "New York",
"city": "New York City",
"zip": "11323"
}
}
},
{
"name": "Bob",
"job": "Project Manager",
"organization": {
"company": {
"employer": "Megasystems",
"department": "R&D"
}
},
"address": {
"location": {
"quadrant": {
"block": 1,
"state": "Texas",
"city": "Austin"
}
}
}
}
]
}
The code I’m trying to implement is here:
// constants and variables are defined here, including API credentials and the filteredEmployers array
//FYI const filteredEmployers = ['Megasystems', 'Bellkrieg'];
//the code then fetches the API data is here
.then((response) => {
return response.json();
})
.then((json) => {
//console.log(typeof json);
//console.log(json);
const people = Array.from(json).flatMap(o => o.People);
return people.filter(person => {
const employer = person?.organization?.company?.employer;
if (typeof employer !== 'string') return true;
const employerIsNotFiltered = filteredEmployers.every(
str => !employer.includes(str)
);
console.log("This is the outputted data: " + employerIsNotFiltered);
return employerIsNotFiltered;
});
})
The desired response is:
[
{
name: 'TJ',
job: 'Software Engineer',
organization: { company: [Object] },
location: { city: 'Boston', state: 'Massachusetts' }
},
{
name: 'Dominique',
job: 'CEO',
organization: { company: [Object] },
city: 'Seattle',
state: 'Washington'
}
]
Any recommendations on how to get this to execute, or alternatives to this method appreciated.
Thanks in advance

Reiterating my comment on your question: You just need to change the line
const people = Array.from(json).flatMap(o => o.People);
to
const people = json.People;
The JSON response that you included in the question is an object, and Response.json() returns a promise which resolves to an already parsed representation of the JSON text response, so in order to access the array at the People property, you only need json.People. Here is a runnable snippet based on the code and data that you showed:
// The JSON data, copied and pasted from the first code block of your question:
const json = `{"Pagination":{"NumberOfPeople":185,"PageSize":200,"PageNumber":1,"NumberOfPages":1},"People":[{"name":"TJ","job":"Software Engineer","organization":{"company":{"employer":"amazon","department":"IT"}},"location":{"city":"Boston","state":"Massachusetts"}},{"name":"Dominique","job":"CEO","organization":{"company":{"employer":"IBM","department":"IT"}},"city":"Seattle","state":"Washington"},{"name":"Enrique","job":"Engineer","organization":{"company":{"employer":"Bellkrieg Megasystems","department":"Construction"}},"location":{"address":{"state":"New York","city":"New York City","zip":"11323"}}},{"name":"Bob","job":"Project Manager","organization":{"company":{"employer":"Megasystems","department":"R&D"}},"address":{"location":{"quadrant":{"block":1,"state":"Texas","city":"Austin"}}}}]}`;
function mockFetch () {
return Promise.resolve({
json: () => Promise.resolve(JSON.parse(json)),
});
}
const filteredEmployers = ['Megasystems', 'Bellkrieg'];
mockFetch()
.then(response => response.json())
.then(json => {
// Change this line:
// const people = Array.from(json).flatMap(o => o.People);
// To:
const people = json.People;
return people.filter(person => {
const employer = person?.organization?.company?.employer;
if (typeof employer !== 'string') return true;
const employerIsNotFiltered = filteredEmployers.every(
str => !employer.includes(str)
);
return employerIsNotFiltered;
});
})
.then(console.log);

Related

Filter an nested Object with filter and map with JavaScript

I know that this is close to a duplicate but I can't get the code to work. I have an object that I need to filter and I'm currently trying to emulate the accepted as an answer the code at Javascript filtering nested arrays
My data object is:
[{
"project_num": "5R01DA012513-23",
"principal_investigators": [{
"profile_id": 2076451,
"full_name": "PK",
"title": ""
}]
},
{
"project_num": "5R01DK118529-03",
"principal_investigators": [{
"profile_id": 8590844,
"full_name": "HW",
"title": "PROFESSOR, SCIENTIFIC DIRECTOR"
}]
},
{
"project_num": "3R01AA025365-05S1",
"principal_investigators": [{
"profile_id": 8730036,
"full_name": "JJ",
"title": "ASSOCIATE PROFESSOR OF PSYCHIATRY"
}]
},
{
"project_num": "1R01HL163963-01",
"principal_investigators": [{
"profile_id": 2084037,
"full_name": "KH",
"title": "ASSOCIATE PROFESSOR"
},
{
"profile_id": 11309656,
"full_name": "AM",
"title": "RESEARCH ASSISTANT PROFESSOR"
}
]
},
{
"project_num": "5R25HL092611-15",
"principal_investigators": [{
"profile_id": 1886512,
"full_name": "CW",
"title": "P"
}]
}
]
and my JavaScript code is:
let payLoad = 1886512
const result = this.reporterData.map(t => {
const principal_investigators = t.principal_investigators.filter(d =>
d.profile_id === payLoad);
return { ...t,
principal_investigators
};
})
I need to pass in a profile_id as a payload and return the objects that will fill a data table.
The data can be 1000's of items and the principla_investigators can be multiple entries. When I use the code that I have it return all of the objects. Can someone point out my error? Thanks
You can try doing like this:
const result = this.reporterData.filter((t) => {
const principal_investigators = t.principal_investigators.filter((d) => d.profile_id === payLoad)
return (principal_investigators.length > 0)
})
I understand that you want an array with all the investigators matching that ID, right?
Try this:
const result = this.reporterData.reduce((previous, current) => {
if (current.principal_investigators) {
current.principal_investigators.forEach(pi => {
if (pi.profile_id === payLoad) {
previous.push(current)
}
});
}
return previous
}, [])
You can also do for loops with the same result:
const result = [];
for (project of this.reporterData) {
if (project.principal_investigators) {
for (pi of project.principal_investigators) {
if (pi.profile_id == payLoad) {
result.push(pi);
}
}
}
}

Want to restructure/modify the API response for required JSON format in Angular project

The API response needs to change in the required JSON format as below. I have mentioned the responses that I am getting.. and also I mentioned the desired format. Please guide me.
It listed the person's data. but I need the persons should be grouped based on department.
The response want I am getting is
{
"statusCode":200,
"message":"OK",
"status":"success",
"response":{
"data":[
{
"name":"John",
"age":30,
"department":"Hardware"
},
{
"name":"Durai",
"age":22,
"department":"Hardware"
},
{
"name":"Durai",
"age":22,
"department":"Software"
},
{
"name":"Durai",
"age":22,
"department":"Software"
}
]
}
}
I want to change the above response into the format like below,
{
"statusCode":200,
"message":"OK",
"status":"success",
"response":{
"data":{
"department":"Hardware",
"persons":[
{
"name":"John",
"age":30,
"department":"Hardware"
},
{
"name":"Durai",
"age":22,
"department":"Hardware"
}
]
},
"department":"Hardware",
"persons":[
{
"name":"Durai",
"age":22,
"department":"Software"
},
{
"name":"Durai",
"age":22,
"department":"Software"
}
]
}
}
Here's one way of approaching it...
let orig_data = [{
"name": "John",
"age": 30,
"department": "Hardware"
},
{
"name": "Durai",
"age": 22,
"department": "Hardware"
},
{
"name": "Durai",
"age": 22,
"department": "Software"
},
{
"name": "Durai",
"age": 22,
"department": "Software"
}
]
let data = [];
orig_data.forEach(el => {
// check to see if we already have a new object ready for this department...
if (data.filter(el2 => el2.department == el.department).length == 0) {
// we don't, so create it and start the persons array
data.push({
department: el.department,
persons: [el]
})
} else {
// we do, so find it and add another person
data.forEach(el3 => {
if (el3.department == el.department) el3.persons.push(el);
})
}
})
console.log(data)

create new city state object

I would like to transform my initial data to desired result, I am struggling with pushing the cities to the array and making sure name key is unique.
initial data
[
{ "city": "Abbeville", "state": "Louisiana" },
{ "city": "Aberdeen", "state": "Maryland" },
{ "city": "Aberdeen", "state": "Mississippi" },
{ "city": "Aberdeen", "state": "South Dakota" },
{ "city": "Aberdeen", "state": "Washington" },
{ "city": "Abilene", "state": "Texas" },
{ "city": "Abilene", "state": "Kansas" },
{ "city": "Abingdon", "state": "Virginia" },
{ "city": "Abington", "state": "Massachusetts" },
{ "city": "Abington", "state": "Massachusetts" },
]
code
let newCityStateObject = cities.map((item, index) => {
console.log("item ", item);
if (item) {
let object = {};
let citiesArray = [];
//set state and create empty array
if (object[item.state] === undefined) {
object.name = item.state;
object.cities = [].push(item.city);
} else {
//key exists so just push to array
if (object[item.state]) {
object.cities.push(item.city);
}
}
console.log("end ", object);
return object;
}
});
my result right now
[
{ state: 'Louisiana', cities: [] },
{ state: 'Maryland', cities: [] },
{ state: 'Mississippi', cities: [] },
{ state: 'South Dakota', cities: [] },
{ state: 'Washington', cities: [] },
{ state: 'Texas', cities: [] },
{ state: 'Kansas', cities: [] },
{ state: 'Virginia', cities: [] },
]
desired result
[
{
"name": "Kentucky",
"cities": [
"Louisville/Jefferson County",
"Lexington-Fayette",
"Bowling Green",
"Owensboro",
"Covington"
]
},
{
"name": "Maryland",
"cities": [
"Baltimore",
"Frederick",
"Rockville",
"Gaithersburg",
"Bowie",
"Hagerstown",
"Annapolis"
]
}
]
Any help/tips or pointing in the right direction to solve this would be greatly appreciated.
You’re basically grouping cities by their state. First of all, array.map is not the proper method for this problem, cus when you group, the input item’s number might not match with the output’s. array.reduce is better option.
let newCityStateObject = cities.reduce((acc, item, index) => {
if (item) {
// this object has state as key, and the desired output array’s item as value
const object = acc.obj;
// if state not found, create new record
if (object[item.state] === undefined) {
const record = { name: item.state, cities: [] }
object[item.state] = record;
acc.array.push(record);
}
const record = object[item.state];
record.cities.push(item.city);
}
return acc;
}, { obj: {}, array: [] }).array;
I like the answer suggested by #hackape.
Here is one more way to consider:
let newCityStateObject = () => {
const statesArr = Array.from(cities, (item) => item.state);
// Remove state duplications
const filteredStates = [...new Set(statesArr)];
// Initializing the name and cities object and array
let result = filteredStates.map((item) => {
return { name: item, cities: [] };
});
// For each cite item, fetch the city to its corresponding result by state
cities.forEach((item) =>
result
.find((element) => element.name === item.state)
.cities.push(item.city)
);
return result;
}

Merge 2 object arrays in json files by key

I'm trying to combine 2 object array in javascript/jquery matching them by the same key (code). These object arrays are stored in 2 separate json files.
I've cut these down as the files are long
Thanks in advance if anyone can help.
Object 1:
[{
"city": "london",
"selfemployed": {
"job" :"Builder",
"code": "abc"
},
"company" : {
"job": "Shopkeeper",
"code": "def"
}
}]
Object 2:
[{
"code": "abc",
"participant": {
"firstname" : "Joe",
"lastname" : "Blogs"
}
},
{
"code": "def",
"participant": {
"firstname" : "Anna",
"lastname" : "Smith"
}
}]
Needed result:
[{
"city": "london",
"selfemployed": {
"job" :"Builder",
"code": "abc",
"participant": {
"firstname" : "Joe",
"lastname" : "Blogs"
}
},
"company" : {
"job": "Shopkeeper",
"code": "def",
"participant": {
"firstname" : "Anna",
"lastname" : "Smith"
}
}
}]
One of my issues is that I'm unable to return the object from the .json files
var file1 = 'url/file1.json';
var file1 = 'url/file2.json';
const joinJson = (file1, file2) => {
$.getJSON(file, function(data1) {
return data1;
});
$.getJSON(file2, function(data2) {
return data2;
});
// do stuff with data1 and data2
}
console.log(joinJson());
You could take a Map and build new objects for the result by selecting the wanted code information for the new object.
This proposal uses rest properties of an object with babel for older user agents.
var cities = [{ city: "london", selfemployed: { job: "Builder", code: "abc" }, company: { job: "Shopkeeper", code: "def" } }],
codes = [{ code: "abc", participant: { firstname: "Joe", lastname: "Blogs" } }, { code: "def", participant: { firstname: "Anna", lastname: "Smith" } }],
codesMap = new Map(codes.map(({ code, participant }) => [code, participant])),
result = cities.map(
({ city, ...items }) =>
Object.assign({ city }, ...Object.entries(items).map(
([k, v]) => ({ [k]: Object.assign({}, v, codesMap.get(v.code)) })
))
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The problem is that you're getting the files asynchronously, and returning data in the callback of that async operation, which goes nowhere. Something like this would be better:
var file1 = 'url/file1.json';
var file1 = 'url/file2.json';
const joinJson = (file1, file2) => {
$.getJSON(file, function(data1) {
// async operation 1 complete. Start operation 2.
$.getJSON(file2, function(data2) {
// async operation 2 complete
// data1 and data2 are now available here
console.log("Data 1:", data1);
console.log("Data 2:", data2);
// This will merge the keys of both objects
// but you can replace it with custom merging logic
var merged = Object.assign(data1, data2);
console.log(merged);
});
});
}
The problem here is that you can't do something like console.log(joinJson());. You may very well need something like a Promise.

NodeJs: Data Transformers like in Laravel PHP Framework

I've created multiple REST API projects using the Laravel framework and basing my code structure on the Laracasts tutorial. However we are deciding to move some projects using NodeJs as a backend. I'm beginning to learn node and I'm trying to replicate it in Node. I was able to do it for a singe object response but for multiple objects I can't seem to make it work.
Here is my controller:
index(req,res) {
User
.findAll()
.then(function(users){
res.json(api.respond(transfomer.transformCollection(users)));
})
.catch(function(error){
res.json(api.respondWithError('users not found',error));
});
}
api controller:
module.exports = {
// response w/o error
respond: function(data,msg,status) {
if (msg == null) {
return {
'status': status || true,
'data': data
};
} else {
return {
'status': true,
'message': msg,
'data': data
};
}
},
// response with error
respondWithError: function(msg,error) {
var self = this;
var status = false;
var data = {
'error': error
};
return this.respond(data,msg,status);
},
};
transformer.js
module.exports = {
// single transformation
transform (user) {
return {
'id' : user.id,
'username': user.username,
'firstname': user.firstname,
'lastname': user.lastname,
'address': user.address,
'phone': user.phone,
'mobile': user.mobile,
'status': user.status
};
},
//
transformCollection(users) {
var self = this;
var data = [];
for (var i = 0; i <= users.length; i++) {
data.push(this.transform(users[i]));
}
return data;
}
};
sample output
{
"status": true,
"data": [
{
"id": 1,
"username": "b#email.com",
"firstname": "Jon",
"lastname": "Doe",
"address": "Homes",
"phone": "+966501212121",
"mobile": "+966501212121",
"status": "NOT VERIFIED"
},
{
"id": 1,
"username": "b#email.com",
"firstname": "Jon",
"lastname": "Doe",
"address": "Homes",
"phone": "+966501212121",
"mobile": "+966501212121",
"status": "NOT VERIFIED"
},
{
"id": 1,
"username": "b#email.com",
"firstname": "Jon",
"lastname": "Doe",
"address": "Homes",
"phone": "+966501212121",
"mobile": "+966501212121",
"status": "NOT VERIFIED"
},
{
"id": 1,
"username": "b#email.com",
"firstname": "Jon",
"lastname": "Doe",
"address": "Homes",
"phone": "+966501212121",
"mobile": "+966501212121",
"status": "NOT VERIFIED"
},
]
}
Sorry for asking this as I'm a bit newb with node. Is it possible to achieve that output as I tried different ways but Im still getting errors. Btw I'm using sequelize for the database.
Thanks.
You can use this:
const options = {
raw: true,
attributes: ['id', 'name', 'code', 'createdAt','updatedAt']
};
country.findAndCountAll(options).then(querySnapshot => {
const total = querySnapshot.count;
resolve({
docs: querySnapshot.rows,
total: total
})
}).catch((err) => {
reject(err)
});
I've found the answer to my question since sequelize is returning the results as an object with additional properties aside from the database results I had to modify the controller to set and convert the results to raw in order for me to get the array of objects from the query results from the database.
index(req,res) {
User
.findAll({ raw: true }) // added "raw: true"
.then(function(users){
res.json(api.respond(transfomer.transformCollection(users)));
})
.catch(function(error){
res.json(api.respondWithError('users not found',error));
});
},
This will return the array of objects from the database and from there the data transformer is working properly. Thank you for all the help.

Categories

Resources