In first API call I'm getting an array of IDs to be able to make another API call to grab revenue key/value pairs, then push it back to the main object(as it doesn't have it by default).
const mainURL =
"https://api.themoviedb.org/3/discover/movie?api_key=2339027b84839948cd9be5de8b2b36da&language=en-US&sort_by=revenue.desc&include_adult=false&include_video=false&page=";
const movieBaseURL =
"https://api.themoviedb.org/3/movie/335?api_key=2339027b84839948cd9be5de8b2b36da&language=en-US";
const apiKey = "2339027b84839948cd9be5de8b2b36da";
let getRevenueByID,revenue, data, response, obj;
let Each_ID_Array = [],
All_ID_Array = [],
All_ID_Array_merged = [],
pages_Array = [1, 2],
keyValueArr = [],
allKeyValueArr = [],
objectArr = [];
responses = [];
newData = [];
let text = "";
//fetch function
let getSearchResultsForOnePage = url => {
//fetch
return fetch(url);
};
//Function to cool down requests
let pause = time => {
// handy pause function to await
return new Promise(resolve => setTimeout(resolve, time));
};
//Get main object for d3 visualisation
getAllSearchResultProfiles = async searchURL => {
let URLs = [];
for (let i = 0; i < pages_Array.length; i++) {
URLs.push(searchURL + pages_Array[i]);
}
console.log(URLs);
for (let url of URLs) {
console.log("sending request");
response = await getSearchResultsForOnePage(url);
console.log("received", response);
responses.push(await response.json());
await pause(500);
}
console.log('responses', responses);
return responses;
};
//Function to get revenue by ID
getRevenueByID = async (arr) => {
let resObj = {}; // Is an complete result
for (let i = 0; i < arr.length; i++) {
console.log("ID is: ", arr[i]);
getRevenueURL = await fetch(
"https://api.themoviedb.org/3/movie/" +
arr[i] +
"?api_key=" +
apiKey +
"&language=en-US"
);
let data = await getRevenueURL.json();
console.log("data received: ", data);
await pause(200);
//return key/value array
keyValueArr = Object.entries(data)[16];
console.table(keyValueArr);
allKeyValueArr.push(keyValueArr);
//convert key/value array to object
obj = Object.assign(
...allKeyValueArr.map(d => ({
[d[0]]: d[1]
}))
);
console.log("object is: ", obj);
resObj[arr[i]] = obj;
console.log("resObj: ", resObj[arr[i]]);
}
console.log("OUTPUT - getRevenueByID: ", resObj);
return resObj;
};
(getFinalObject = async () => {
getAllSearchResultProfiles(mainURL).then(async (data) => {
//get movie ID's
for (let i = 0; i < data.length; i++) {
Each_ID_Array = data[i].results.map(d => d.id);
All_ID_Array.push(Each_ID_Array);
console.table('All ID Array', All_ID_Array);
All_ID_Array_merged = [].concat.apply([], All_ID_Array);
console.table('All ID Array merged',All_ID_Array_merged);
console.log('data[i].results: ',data[i].results);
obj = await getRevenueByID(All_ID_Array_merged);
console.log('obj is', obj);
//inject revenue key/value
Object.keys(data[i].results).forEach(key => {
console.log("The name of the current key: ", key);
console.log("The value of the current key: ", data[i].results[key]);
data[i].results[key]["revenue"] = obj[data[i].results[key].id]["revenue"];
console.log('data[i].results[key]["revenue"]: ', data[i].results[key]["revenue"]);
});
}
console.log('data', data);
Data I'm getting is in the following format [{…}, {…}]. So instead of an array of objects I'm trying to get an array of one object [{...}] inside
newData = data.map(item =>
Object.assign({}, item)
);
console.log('data for visualisation is:',newData);
}).catch(error => console.log(error));
})();
I think you have to reduce the array:
const data = [{a:1}, {b:2}];
const newData = data.reduce((acc,curr) => ({...acc, ...curr}), {});
console.log(newData); // { a: 1, b: 2 }
Related
** Update: The answer below works great up to the merge. I had to add some iterations into getL2 and getL3 to make all the calls necessary. The issue seemed to be that some of the tasks from L1 did not have a child at L2, and some L2 did not have an L3. So the final results has some empty arrays. the final result before the merge looks like below. right now, the merge function returns the L1 data with no children added.
var result = [
[{
"ID": 1,
"title": "Task 1",
"org": "A"
}, {
"ID": 2,
"title": "Task 2",
"org": "B"
}],
[{}, {},
{
"ID": 10,
"ParentID": 2
}, {
"ID": 11,
"ParentID": 2
}
],
[{}, {}, {
"ID": 20,
"ParentID": 10
}, {
"ID": 21,
"ParentID": 10
}]
]
I continue to struggle with async and promises, despite the amazing help on stack. I tried to reverse engineer some similar posts with no success. I am trying to chain 3 functions that will make multiple REST calls in SharePoint 2013. the first call grabs all items in list taskL1 that match the organization. it uses the ID's to create a set of unique entries. then a second call against taskL2 is made using the the set to find all entries that have those id's in the parentID column. It then creates a set of those IDs to make a final call against taskL3 and matches those IDs to the parentID column in that list. I need to pass all three results along until a final function will merge the data into a nested object.Bascially, put all the L3 tasks under the correct L2 and all the L2 under the correct L1. I can't seem to keep all 3 results passing along until the end and available to a follow on function. https://jsfiddle.net/75ghvms8/
var setL1 = new Set();
var setL2 = new Set();
var taskL1 = [{"id":1,"title":"Task 1","org":"A"},{"id":2,"title":"Task 2","org":"B"},{"id":3,"title":"Task 3","org":"A"}]
var taskL2 = [{"id":20,"parentID":1},{"id":21,"parentID":1},{"id":22,"parentID":2},{"id":23,"parentID":2}]
var taskL3 = [{"id":100,"parentID":20},{"id":111,"parentID":21},{"id":120,"parentID":22},{"id":220,"parentID":23}]
getL1(taskL1,'A').then(()=>{getL2(taskL2,setL1)}).then(()=>{getL3(taskL3,setL2)});
async function getL1(srcList,org){
const l1List = await getData(srcList,org);
console.log(l1List);
return l1List
}
async function getL2(srcList,set){;
const l2List = await getData2(srcList,set);
console.log(l2List);
return l2List
}
async function getL3(srcList,set){
const l3List = await getData3(srcList,set);
console.log(l3List);
return l3List
}
async function getData(srcList,org,result={}) {
const listItems = await getTaskItems(srcList,org);
result = listItems;
return result;
}
async function getData2(srcList,item,result={}) {
let j = 0;
for(let i of item) {
const listItems = await getTaskItems2(srcList,i)
result[j] = listItems;
j++
}
return result
}
async function getData3(srcList,item,result={}) {
let j = 0;
for(let i of item) {
const listItems = await getTaskItems3(srcList,i)
result[j] = listItems;
j++
}
return result
}
function getTaskItems(srcList,org) {
const arrData = srcList.filter(obj=> {
return obj.org === org;
});
for (let i = 0; i < arrData.length; i++) {
setL1.add(arrData[i].id);
}
return {arrData,setL1}
}
function getTaskItems2(srcList,id) {
const arrData = srcList.filter(obj=> {
return obj.parentID === id;
});
for (let i = 0; i < arrData.length; i++) {
setL2.add(arrData[i].id);
}
return {arrData,setL2}
}
function getTaskItems3(srcList,id) {
const arrData = srcList.filter(obj=> {
return obj.parentID === id;
});
return arrData;
}
// real functions are spRest-Lib functions
/*
function getTaskItems(srcList, org) {
return new Promise((resolve,reject) =>{
sprLib.list(srcList).getItems({
listCols: {
columns here
}
})
.then(function(arrData){
for (let i = 0; i < arrData.length; i++) {
setL1.add(arrData[i].ID);
}
resolve(arrData);
})
.catch(function(errMsg) {console.log(errMsg);});
})
}
*/
You'll need to tweak some key names. Promise chaining is achieved by returning custom objects {l1: [], l2: [], l3: []}. Merge can probably be done as you go along each step, but instead here is one way to do it with explicit merge step.
var taskL1 = [{"id":1,"title":"Task 1","org":"A"},{"id":2,"title":"Task 2","org":"B"},{"id":3,"title":"Task 3","org":"A"}]
var taskL2 = [{"id":20,"parentID":1},{"id":21,"parentID":1},{"id":22,"parentID":2},{"id":23,"parentID":2}]
var taskL3 = [{"id":100,"parentID":20},{"id":111,"parentID":21},{"id":120,"parentID":22},{"id":220,"parentID":23}]
async function getL1(org) {
return new Promise((resolve, reject) => {
// assuming some external reqeust
resolve({ l1:
taskL1.filter((item) => item.org === org)
});
})
}
async function getL2(l1Result) {
return new Promise((resolve, reject) => {
const allL1Ids = Array.from(new Set(Object.values(l1Result.map((item) => item.id))));
// assuming some external request
const filteredList = taskL2.filter((item) => allL1Ids.indexOf(item.parentID !== -1));
resolve({ l1: l1Result, l2: filteredList});
})
}
async function getL3(l1Result, l2Result) {
return new Promise((resolve, reject) => {
const allL2Ids = Array.from(new Set(Object.values(l2Result.map((item) => item.id))));
// assuming some external request
const filteredList = taskL3.filter((item) => allL2Ids.indexOf(item.parentID !== -1));
resolve({l1: l1Result, l2: l2Result, l3: filteredList})
})
}
function groupByKey(items, key) {
return items.reduce(function(results, item) {
(results[item[key]] = results[item[key]] || []).push(item);
return results;
}, {});
}
function merge(l1, l2, l3) {
// we want to put l3.parentID into l2.id.children
let l3ByParentId = groupByKey(l3, "parentID");
let l2ById = groupByKey(l2, "id");
Object.keys(l3ByParentId).forEach((parentId) => {
if (l2ById[parentId]) {
l2ById[parentId][0]['l3children'] = l3ByParentId[parentId];
}
});
let l2ByParentId = groupByKey(Object.values(l2ById).map((item) => item[0]), "parentID");
let l1ById = groupByKey(l1, "id");
Object.keys(l2ByParentId).forEach((parentId) => {
if (l1ById[parentId]) {
l1ById[parentId][0]['l2children'] = l2ByParentId[parentId];
}
});
return Object.values(l1ById).map(item => item[0]);
}
getL1("A")
.then((result) => {
return getL2(result.l1)
})
.then((result) => {
return getL3(result.l1, result.l2)
})
.then((result) => {
return merge(result.l1, result.l2, result.l3)
})
.then((result) => {
console.log(JSON.stringify(result, null, 2));
})
How do I get the value of this list to return to another function? I tried to use promise and async/await but it looks like it didn't work properly, now I have a problem with 'follow' of undefined, can someone help me
var parser = require("parse-whois");
var whois = require("node-whois");
async function getList(getRemainingDays = false) {
let finalList = [];
var domains = [
"rundeck.compasso.com.br",
"c.btg360.com.br",
"api-prd.reservapto.com.br",
];
try {
for (let i = 2; i < domains.length; i++) {
finalList.push(
whois
.lookup(domains[i])
.then((data) => {
let list = [];
var dados = parser.parseWhoIsData(data);
const expires = dados
.filter((one) => one.attribute === "expires")
.pop();
const dateExpires = expires.value;
list.push(domains[i]);
list.push(dateExpires);
return list;
})
.catch((err) => {
console.log(err);
})
);
}
} catch (error) {
console.log(error);
}
let resultList = await Promise.all(finalList);
return resultList;
}
async function test() {
var list = await getList(true);
console.log("");
console.log(list);
console.log("");
}
test();
Answer:
const whois = require("whois-checker-v2");
async function getList() {
var domains = [
"rundeck.compasso.com.br",
"c.btg360.com.br",
"api-prd.reservapto.com.br",
]
let finalList = [];
for (let i = 0; i < domains.length; i++) {
finalList.push(
(result = await whois
.lookup(domains[i])
.then((result) => {
var list = [];
list.push(domains[i]);
list.push(result.expirationDate);
return list;
})
.catch((err) => {
//console.log(err);
}))
);
}
let resultList = await Promise.all(finalList);
return resultList;
}
async function test() {
var lista = await getList();
console.log(lista);
}
test();
result:
[
[ 'c.btg360.com.br', '2023-02-16T03:00:00.000Z' ],
[ 'api-prd.reservapto.com.br', '2022-12-03T03:00:00.000Z' ],
[ 'api-prd.koerich.com.br', '2024-06-04T03:00:00.000Z' ],
[ 'gmfy.compasso.com.br', '2025-06-13T03:00:00.000Z' ],
[ 'compassouol.com.br', '2022-02-13T03:00:00.000Z' ],
[ 'rancher.compasso.com.br', '2025-06-13T03:00:00.000Z' ]
]
I'm trying to build a citation generator from json in an API with data about images, stored in key-value pairs. I can get the data to return to the screen, but it always includes undefined in the citation. Sample manifest returns undefined as the creator since that isn't listed in this particular record. How can I keep any undefined value from being returned? I've tried changing the forEach to map, filtering at allMetadata by string length, using if !== undefined at insertCitation, and versions of those in different spots in the code.
EDIT: updated to provide full code, including print to page
(function () {
'use strict';
const buildCitation = {
buildMetadataObject: async function (collAlias, itemID) {
let response = await fetch('/iiif/info/' + collAlias + '/' + itemID + '/manifest.json');
let data = await response.json()
let allMetadata = data.metadata
let citationData = {};
allMetadata.forEach(function (kvpair) {
if (kvpair.value == undefined) {
return false;
} else if (kvpair.label === 'Title') {
citationData.itemTitle = kvpair.value;
} else if (kvpair.label === 'Creator') {
citationData.itemCreator = kvpair.value;
} else if (kvpair.label === 'Repository') {
citationData.itemRepository = kvpair.value;
} else if (kvpair.label === 'Collection Name') {
citationData.itemCollection = kvpair.value;
} else if (kvpair.label === 'Owning Institution') {
citationData.itemOwning = kvpair.value;
} else if (kvpair.label === 'Date') {
citationData.itemDate = kvpair.value;
} else if (kvpair.label === 'Storage Location') {
citationData.itemStorage = kvpair.value;
}
return true;
});
return citationData;
},
insertCitation: function (data) {
var testTitle = data.itemTitle;
console.log(testTitle);
const itemCite = `Citation: "${data.itemTitle}," ${data.itemDate}, ${data.itemCreator}, ${data.itemCollection}, ${data.itemOwning}, ${data.itemStorage}, ${data.itemRepository}.`;
const citationContainer = document.createElement('div');
citationContainer.id = 'citation';
citationContainer.innerHTML = itemCite;
// CHANGED to innerHTML instead of innerText because you may want to format it at some point as HTML code.
if (testTitle) {
document.querySelector('.ItemView-itemViewContainer').appendChild(citationContainer);
}
}
}
document.addEventListener('cdm-item-page:ready', async function (e) {
const citationData = await buildCitation.buildMetadataObject(e.detail.collectionId, e.detail.itemId);
console.log({ citationData });
buildCitation.insertCitation(citationData);
});
document.addEventListener('cdm-item-page:update', async function (e) {
document.getElementById('citation').remove();
const citationData = await buildCitation.buildMetadataObject(e.detail.collectionId, e.detail.itemId);
console.log({ citationData });
buildCitation.insertCitation(citationData);
});
})();
I've simplified your program. The undefined is coming from the fact that there is no item with label Date
const mappings = {
Date: 'itemDate',
Title: 'itemTitle',
Creator: 'itemCreator',
Repository: 'itemRepository',
'Storage Location': 'itemStorage',
'Owning Institution': 'itemOwning',
'Collection Name': 'itemCollection',
}
async function buildMetadataObject(collAlias, itemID) {
let response = await fetch('https://teva.contentdm.oclc.org/iiif/info/p15138coll25/1421/manifest.json');
let data = await response.json()
return data.metadata.reduce(
(acc, { label, value }) => ({ ...acc, [ mappings[label] ]: value }),
{}
)
}
function insertCitation(data) {
var testTitle = data.itemTitle;
const fieldBlackList = ['itemTitle'];
const itemCite = `Citation: "${data.itemTitle}," ${
Object.values(mappings).reduce((acc, cur) => {
if (fieldBlackList.includes(cur)) return acc;
const value = data[cur];
return value ? [...acc, value] : acc
}, []).join(', ')
}.`;
console.log(itemCite);
}
//MAIN PROGRAM
(async() => {
const citationData = await buildMetadataObject();
insertCitation(citationData);
})()
I'm trying to get the top 5 countries with more covid cases, but when i tried to adapt another code to this, i got an error.
fetch("https://pomber.github.io/covid19/timeseries.json")
.then(response => response.json())
.then(data => {
var countryArr = Object.keys(data).map(i => i);
countryArr.forEach((country) => {
let countryData = data[country];
countryData = countryData[countryData.length - 1];
})
let countries = getCovidRank(countryArr, message)
countries.map((countryData, index) => {
countries[index] = `\\🔹 #${index+1} | **Country**: \`\`${countryData[0]}\`\` | **Confirmed**: \`\`${countryData[0].confirmed}\`\``
})
//The rest of the code will always work, the problem is up there
}
This is the getCovidRank file:
getCovidRank: (countryArr, message) => {
let countryList = []
for(var country in countryArr) {
let countryData = countryArr.confirmed
countryList.push([countryArr, (countryData[country])])
}
countryList.sort((countryData1, countryData2) => {
return countryData2[1] - countryData1[1] || countryData2[2] - countryData1[2]
})
return countryList;
}
I really hope you can help me, i'm trying to learn how to do this. The code below shows the global cases (This code is good):
var worldStats = { confirmed: 0, recovered: 0, deaths: 0 };
var countryArr = Object.keys(data).map(i => i);
countryArr.forEach((country) => {
let countryData = data[country];
// pick last object for today data
countryData = countryData[countryData.length - 1];
worldStats.confirmed += countryData.confirmed;
worldStats.recovered += countryData.recovered;
worldStats.deaths += countryData.deaths;
});
// world data
var worldChart = [];
countryArr.forEach((country) => {
let countryData = data[country];
countryData.forEach((dailyData, index) => {
if (worldChart[index] === undefined) {
var worldStats = { date: dailyData.date, confirmed: dailyData.confirmed, recovered: dailyData.recovered, deaths: dailyData.deaths };
worldChart.push(worldStats);
} else {
worldChart[index].confirmed += dailyData.confirmed;
worldChart[index].recovered += dailyData.recovered;
worldChart[index].deaths += dailyData.deaths;
}}
); ""
})
return message.channel.send(` __Coronavirus:__\n **Active cases**: \`\`${worldStats.confirmed - worldStats.recovered - worldStats.deaths}\`\`\n **Recovered**: \`\`${worldStats.recovered}\`\`\n**Deaths**: \`\`${worldStats.deaths}\`\``)
}
Here is a really simple demo of showing the top 5 countries by confirmed status.
EDIT Just added a working snippet
function init() {
fetch("https://pomber.github.io/covid19/timeseries.json")
.then(response => response.json())
.then(data => {
var countries = [];
Object.keys(data).forEach(country => {
var total = data[country].reduce(
(acc, val) => (acc += val.confirmed),
0
);
countries.push({
name: country,
confirmed: total
});
});
countries.sort((a, b) => a.confirmed > b.confirmed ? -1 : 1);
document.getElementById('div').innerHTML = countries.slice(0, 5).map(c => c.name + ' ' + c.confirmed).join('<br>');
})
}
init();
<div id="div"></div>
I have an API call in api.js:
export const getGraphData = (domain, userId, testId) => {
return axios({
url: `${domain}/api/${c.embedConfig.apiVersion}/member/${userId}/utests/${testId}`,
method: 'get',
});
};
I have a React helper that takes that data and transforms it.
import { getGraphData } from './api';
const dataObj = (domain, userId, testId) => {
const steps = getGraphData(domain, userId, testId)
.then((result) => {
return result.attributes;
});
console.log(steps);
// const steps = test.get('steps');
const expr = /select/;
// build array of steps that we have results in
const resultsSteps = [];
steps.forEach((step) => {
// check for types that contain 'select', and add them to array
if (expr.test(step.get('type'))) {
resultsSteps.push(step);
}
});
const newResultsSteps = [];
resultsSteps.forEach((item, i) => {
const newMapStep = new Map();
const itemDescription = item.get('description');
const itemId = item.get('id');
const itemOptions = item.get('options');
const itemAnswers = item.get('userAnswers');
const newOptArray = [];
itemOptions.forEach((element) => {
const optionsMap = new Map();
let elemName = element.get('value');
if (!element.get('value')) { elemName = element.get('caption'); }
const elemPosition = element.get('position');
const elemCount = element.get('count');
optionsMap.name = elemName;
optionsMap.position = elemPosition;
optionsMap.value = elemCount;
newOptArray.push(optionsMap);
});
newMapStep.chartType = 'horizontalBar';
newMapStep.description = itemDescription;
newMapStep.featured = 'false';
newMapStep.detailUrl = '';
newMapStep.featuredStepIndex = i + 1;
newMapStep.id = itemId;
newMapStep.isValid = 'false';
newMapStep.type = 'results';
const listForNewOptArray = List(newOptArray);
newMapStep.data = listForNewOptArray;
newMapStep.userAnswers = itemAnswers;
newResultsSteps.push(newMapStep);
});
return newResultsSteps;
};
export default dataObj;
The issue is steps, when logged outside the .then() returns a Promise {<pending>}. If I log results.attributes inside the .then(), I see the data fully returned.
You need to wait until your async call is resolved. You can do this by chaining on another then:
getGraphData(domain, userId, testId)
.then((result) => {
return result.attributes;
})
.then(steps => {
// put the rest of your method here
});
You can also look at async/await if your platform supports it which would allow code closer to your original
const steps = await getGraphData(domain, userId, testId)
.then((result) => {
return result.attributes;
});
// can use steps here
You have 2 options to transform your fetched data :
1st option : create a async function that returns a promise with the modified data :
const dataObj = (domain, userId, testId) => {
return getGraphData(domain, userId, testId).then((result) => {
const steps = result.attributes;
const expr = /select/;
// build array of steps that we have results in
const resultsSteps = [];
steps.forEach((step) => {
// check for types that contain 'select', and add them to array
if (expr.test(step.get('type'))) {
resultsSteps.push(step);
}
});
const newResultsSteps = [];
resultsSteps.forEach((item, i) => {
const newMapStep = new Map();
const itemDescription = item.get('description');
const itemId = item.get('id');
const itemOptions = item.get('options');
const itemAnswers = item.get('userAnswers');
const newOptArray = [];
itemOptions.forEach((element) => {
const optionsMap = new Map();
let elemName = element.get('value');
if (!element.get('value')) {
elemName = element.get('caption');
}
const elemPosition = element.get('position');
const elemCount = element.get('count');
optionsMap.name = elemName;
optionsMap.position = elemPosition;
optionsMap.value = elemCount;
newOptArray.push(optionsMap);
});
newMapStep.chartType = 'horizontalBar';
newMapStep.description = itemDescription;
newMapStep.featured = 'false';
newMapStep.detailUrl = '';
newMapStep.featuredStepIndex = i + 1;
newMapStep.id = itemId;
newMapStep.isValid = 'false';
newMapStep.type = 'results';
const listForNewOptArray = List(newOptArray);
newMapStep.data = listForNewOptArray;
newMapStep.userAnswers = itemAnswers;
newResultsSteps.push(newMapStep);
});
return newResultsSteps;
});
};
With es7 async/await syntax it should be :
const dataObj = async (domain, userId, testId) => {
const result = await getGraphData(domain, userId, testId);
const steps = result.attributes;
... modify the data
}
Then keep in mind that this function returns a promise, you'll need to wait for it to get the result, example in a react component :
componentDidMount(){
dataObj('mydomain', 'myuserId', 'mytestId').then((res) => {
this.setState({ data: res });
}
}
The component will update when the promise is resolve, you can then use the data (you'll need to handle the undefined data state in render method)
2nd option : Create a sync function to modify the data :
const dataObj = (steps) => {
const expr = /select/;
const resultsSteps = [];
steps.forEach((step) => {
...
}
return newResultsSteps;
};
To have the same result as option 1 in our component we'll use it like this :
componentDidMount(){
getGraphData('mydomain', 'myuserId', 'mytestId').then((res) => {
const modifiedData = dataObj(res);
this.setState({ data: modifiedData });
}
}
That's how promises work. The data is not ready when you are trying to use it so you should move all your processing into the .then. The reason your variable is a Promise {<pending>} is because you can chain other things onto it.
Something like:
steps.then((steps) => {
...
});