How to create array and pass them in Node.js - javascript

I'd like to pass fetched data like following array.
{ category: ['Animals','Vehicles']
difficulty: ['easy','medium']
}
I tried something like following, getCategory.push(quiz.getCategory(2)),
But I encountered following errors.
Unexpected token .
I confused how to pass array like data.
If someone has opinon,please let me know.
Thanks
const API_KEY="https://opentdb.com/api.php?amount=10&type=multiple";
const fetch = require('node-fetch');
const Quiz=require("../public/javascripts/quiz");
module.exports={
getQuiz:function(resp){
fetch(API_KEY)
.then(response => response.json())
.then(json => { const quiz = new Quiz(json);
resp.send({
getCategory:quiz.getCategory(1),
getCategory.push(quiz.getCategory(2)),
getDifficulty:quiz.getDifficulty(1),
getDifficulty.push(quiz.getDifficulty(2))
});
});
}
};
My class is following.
class Quiz {
constructor(quizData){
this._quizzes = quizData.results;
this._correctAnswersNum = 0;
}
getNumOfQuiz(){
return this._quizzes.length;
}
getCategory(index){
return this._quizzes[index-1].category;
}
getDifficulty(index){
return this._quizzes[index-1].difficulty;
}
}
module.exports = Quiz;
fetch(API_KEY) returned something like following.
results:
[ { category: 'Animals',
type: 'multiple',
difficulty: 'easy',
question: 'What do you call a baby bat?',
correct_answer: 'Pup',
incorrect_answers: [Array] },
{ category: 'Vehicles',
type: 'multiple',
difficulty: 'medium',
question: 'Which supercar company is from Sweden?',
correct_answer: 'Koenigsegg',
incorrect_answers: [Array] },
{ category: 'Entertainment: Board Games',
type: 'multiple',
difficulty: 'hard',
question: 'Which board game was first released on February 6th, 1935?',
correct_answer: 'Monopoly',
incorrect_answers: [Array] }]

I didn't see how exactly we need to use the Class methods in this implementation..
But we can go as follows.
This is the data we are receiving
const data = [ { category: 'Animals',
type: 'multiple',
difficulty: 'easy',
question: 'What do you call a baby bat?',
correct_answer: 'Pup',
incorrect_answers: [Array] },
{ category: 'Vehicles',
type: 'multiple',
difficulty: 'medium',
question: 'Which supercar company is from Sweden?',
correct_answer: 'Koenigsegg',
incorrect_answers: [Array] },
{ category: 'Entertainment: Board Games',
type: 'multiple',
difficulty: 'hard',
question: 'Which board game was first released on February 6th, 1935?',
correct_answer: 'Monopoly',
incorrect_answers: [Array] }];
The data structure we want to send as in response.
const finalResponse = {
category : [],
difficulty : []
}
Looping over actual data, and collect the data in finalResponse. May be if you already know the index of data you can make the use if Class as mentioned in question. For now we have used data array prototype method forEach to loop over each datum as shown below.
data.forEach(function({category, difficulty}){
finalResponse.category.push(category);
finalResponse.category.push(difficulty);
})
finally send the collected data as response
res.send(finalResponse);

Answer 1 (quick fix):
const API_KEY="https://opentdb.com/api.php?amount=10&type=multiple";
const fetch = require('node-fetch');
const Quiz=require("../public/javascripts/quiz");
module.exports={
getQuiz:function(resp){
fetch(API_KEY)
.then(response => response.json())
.then(json => { const quiz = new Quiz(json);
resp.send({
getCategory:[quiz.getCategory(1), quiz.getCategory(2)],
getDifficulty:[quiz.getDifficulty(1),quiz.getDifficulty(2)]
});
});
}
};
Answer 2 (correct way):
class Quiz : introduce new method to get array | getPropArray() // I'm bad at naming
class Quiz {
constructor(quizData){
this._quizzes = quizData.results;
this._correctAnswersNum = 0;
}
getNumOfQuiz(){
return this._quizzes.length;
}
getCategory(index){
return this._quizzes[index-1].category;
}
getDifficulty(index){
return this._quizzes[index-1].difficulty;
}
/**
* get array of prop (property)
* #param {string} prop
* #param {number} start
* #param {number} end
*/
getPropArray(prop, start=1, end=this._quizzes.length){
let res = [];
for (let i=start-1; i<=end-1; i++){
res.push(this._quizzes[i][prop]);
}
return res;
}
}
module.exports = Quiz;
now you can add new property to your response if you want, idk what logic you wanna use to choose result[index] but here^ you can apply a range.
const API_KEY="https://opentdb.com/api.php?amount=10&type=multiple";
const fetch = require('node-fetch');
const Quiz=require("../public/javascripts/quiz");
module.exports={
getQuiz:function(resp){
fetch(API_KEY)
.then(response => response.json())
.then(json => { const quiz = new Quiz(json);
resp.send({
getCategory: quiz.getPropArray('category' ),
getDifficulty: quiz.getPropArray('difficulty')
});
});
}
};

Related

JavaScript, fetch, API

i want to do the following: get a random name with fetch from this website https://swapi.dev/api/people/, which i did and i can see it in my html page then i want also to get a random planet, here i need to access the homeworld key, and to return the link, before returning the link i formatted to get a random url and from this one i also have to show the name of the planet on my page. The first fetch works fine, at least i think but the 3rd .then() is not working or at least i don't know how to access the information from the homeworld url. This is my first time trying fetch() and it will be nice if you guys can help me telling where i did wrong in code and maybe different solutions but not so complicated :D tnks
let randomNumber = Math.floor(Math.random()*9)
const fetchPromise = fetch("https://swapi.dev/api/people/");
let test
let test2
let planets = document.querySelector('#age')
fetchPromise
.then((response) => {
if (!response.ok) {
throw new Error(`Http error: ${response.status}`);
}
return response.json();
})
.then((json) => {
console.log(json.results[randomNumber].name)
showRandomUserData(json)
test = json.results[0].homeworld
test = test.slice(0, -2)
// console.log(test + randomNumber + "/");
// console.log(test + "/" + randomNumber + "/");
test = test + randomNumber + "/";
return fetch(test)
// return fetch("https://swapi.dev/api/planets/2/");
})
.then(response => response.json()).then(json =>
{ test2=json.name
console.log(test2);
planets.innerHTML = test2
})
showRandomUserData = (randomUser) => {
document.querySelector("#name").innerHTML =
randomUser.results[randomNumber].name;
}
Solved
Here's a simple solution that uses fetch() to grab data from both those URLs and then insert all the people and the one planet that is returned into your web page:
function myFetch(...args) {
return fetch(...args).then(response => {
if (!response.ok) {
throw new Error(`fetch failed with status ${response.status}`);
}
return response.json();
});
}
Promise.all([
myFetch("https://swapi.dev/api/people/"),
myFetch("https://swapi.dev/api/planets/2/")
]).then(([people, planet]) => {
const peopleDiv = document.getElementById("people");
let peopleHTML = "";
for (let p of people.results) {
peopleHTML += `<div>${p.name}</div>`;
}
peopleDiv.innerHTML = peopleHTML;
const planetDiv = document.getElementById("planets");
let planetHTML = `<div>${planet.name}</div>`;
planetDiv.innerHTML = planetHTML;
}).catch(err => {
console.log(err);
});
<div id="people"></div>
<hr>
<div id="planets"></div>
As for using the results, the people URL returns a structure that looks like this:
{
count: 82,
next: 'https://swapi.dev/api/people/?page=2',
previous: null,
results: [
{
name: 'Luke Skywalker',
height: '172',
mass: '77',
hair_color: 'blond',
skin_color: 'fair',
eye_color: 'blue',
birth_year: '19BBY',
gender: 'male',
homeworld: 'https://swapi.dev/api/planets/1/',
films: [Array],
species: [],
vehicles: [Array],
starships: [Array],
created: '2014-12-09T13:50:51.644000Z',
edited: '2014-12-20T21:17:56.891000Z',
url: 'https://swapi.dev/api/people/1/'
},
{
name: 'C-3PO',
height: '167',
mass: '75',
hair_color: 'n/a',
skin_color: 'gold',
eye_color: 'yellow',
birth_year: '112BBY',
gender: 'n/a',
homeworld: 'https://swapi.dev/api/planets/1/',
films: [Array],
species: [Array],
vehicles: [],
starships: [],
created: '2014-12-10T15:10:51.357000Z',
edited: '2014-12-20T21:17:50.309000Z',
url: 'https://swapi.dev/api/people/2/'
}
}
So, you have people.results which is an array and you can access people.results[n] to get an item from that array. That item will be an object which has properties like .name, .height, etc...
The specific planet URL you show returns a single planet object like this:
{
name: 'Alderaan',
rotation_period: '24',
orbital_period: '364',
diameter: '12500',
climate: 'temperate',
gravity: '1 standard',
terrain: 'grasslands, mountains',
surface_water: '40',
population: '2000000000',
residents: [
'https://swapi.dev/api/people/5/',
'https://swapi.dev/api/people/68/',
'https://swapi.dev/api/people/81/'
],
films: [
'https://swapi.dev/api/films/1/',
'https://swapi.dev/api/films/6/'
],
created: '2014-12-10T11:35:48.479000Z',
edited: '2014-12-20T20:58:18.420000Z',
url: 'https://swapi.dev/api/planets/2/'
}
So, you access properties on that object as in planet.name.
Notice that the people results are paged. There are 82 total results, but only 10 come in this first result. The rest come with results for other pages such as https://swapi.dev/api/people/?page=2.
Similar to this answer but using async/await to avoid callback hell. If you can, try using this approach. Why?
Excellent recommendation in that answer by jfriend00 to use Promise.all instead of separate fetch calls, as that enables fetching to happen in parallel. To know more.
sandbox to test and try
const fetchData = async (...args) => {
try {
const response = await fetch(...args);
return response.json();
} catch (err) {
throw new Error(`fetch failed with status ${err?.message}`);
}
};
const updateDOM = (people, planet) => {
document.getElementById("people").innerHTML =
people.results.reduce((s, p) => s + `<div>${p.name}</div>`, "");
document.getElementById("planets").innerHTML = `<div>${planet.name}</div>`;
};
const populateData = async () => {
try {
const [people, planet] = await Promise.all([
fetchData("https://swapi.dev/api/people/"),
fetchData("https://swapi.dev/api/planets/2/"),
]);
// do stuff with 'people' or 'planet'
// example, get
// const firstPersonsHomeworld = people.results[0].homeworld;
// console.log(firstPersonsHomeworld);
// or
// const planetName = planet.name;
// console.log(planetName);
updateDOM(people, planet);
} catch (err) {
// errorHandler(err);
console.error(err);
}
};
// start app
populateData();

How can I access fetched data with multiple layers?

I need help trying to access the data the is fetched from an API? The only thing I can do is game.results which I show lower. Everything else I try just outputs "undefined". I'm not sure what else to try that is why I am asking because I have runout of ways to fix this.
function showGames()
{
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Host': 'sportspage-feeds.p.rapidapi.com',
'X-RapidAPI-Key': '<KEY>'
}
};
let url = 'https://sportspage-feeds.p.rapidapi.com/games?league=NBA&date=2022-04-28';
fetch(url, options)
.then(res => {
return res.json();
})
.then((data) => {
const games = data;
let game = games;
let result = `<h2> NBA GAMES</h2>`;
console.log(game.results);
for(let i = 0; i < game.length; i++)
{
thisGame = game[i];
result += `
<div>
<h1>${game.results.summary}</h1>
</div>
`;
}
document.getElementById("games").innerHTML = result;
});
}
window.onload=showGames();
This is what one of the outputs of data.results looks like. I'm not sure how I can access the data in here like summary. I've tried using game.results.summary but it just outputs undefined.
[ { schedule: { date: '2022-04-28T23:00:00.000Z', tbaTime: false },
summary: 'Philadelphia 76ers # Toronto Raptors',
details:
{ league: 'NBA',
seasonType: 'postseason',
season: 2021,
conferenceGame: true,
divisionGame: true },
status: 'final',
teams: { away: [Object], home: [Object] },
lastUpdated: '2022-04-29T01:38:41.138Z',
gameId: 284279,
venue:
{ name: 'Scotiabank Arena',
city: 'Toronto',
state: 'ON',
neutralSite: false },
odds: [ [Object] ],
scoreboard:
{ score: [Object],
currentPeriod: 4,
periodTimeRemaining: '0:00' } },
This statement in your loop:
game = game[i];
overwrites the array game and breaks the whole thing. You need a variable to use in the loop that is separate from the game array:
let thisGame = game[i];

how to filter and get limit amount of data using javascript

I have an array which contains some java script objects and I am using ejs for display data but the problem is - that I have to filter that data in the bases of req.params.id and want to next 2 data objects..! after filtering data -- please help
my code is -
app.get("/:id", (req, res) => {
const requestParams = _.lowerCase(req.params.id);
let obj = blogData.find((o) => o.heading >= "Yoga-During-COVID");
console.log(obj);
blogData.forEach(function (post) {
const storedTitel = _.lowerCase(post.heading);
if (storedTitel === requestParams) {
res.render("blogfullDetail", {
date: post.date,
heading: post.heading,
subheading: post.subheading,
discription: post.discription,
discription2: post.discription2,
author: post.author,
authorImage: post.authorImage,
mainImg: post.mainImg,
});
}
});
});
data file -
Use a combination of findIndex and slice. findIndex returns the index of the matching element and slice returns a sub-array from that index to a computed higher index...
let blogData = [{
id: 1,
title: 'yoga is good'
},
{
id: 32,
title: 'yoga helps you stretch'
},
{
id: 12,
title: 'covid yoga is good too'
},
{
id: 41,
title: 'no such thing as too much yoga'
},
{
id: 57,
title: 'is hot yoga too hot'
}
];
// say you need the post about covid...
let targetTitle = 'covid yoga is good too';
let index = blogData.findIndex(p => p.title === targetTitle);
// with the index, answer a slice of the blogs
// starting at that index, ending 3 later
let posts = blogData.slice(index, index + 3);
console.log(posts)

TypeORM, manyToMany I cannot save array object with its relations with one request

I have two different mutations that I have saved the coordinates in the database createCoordinate, createCoordinateMultiple. In the first, I can easily record a single object and get the response with its relations.
But I can't get the mutation I'm trying to write for multiple operations correctly. Can you help me please ?
#Authorized('ADMIN')
#Mutation(() => Coordinate)
async createCoordinate(
#Arg('coordinate') input: CreateCoordinateInput
): Promise<Coordinate> {
const coordinate = new Coordinate();
coordinate.lat = input.lat;
coordinate.lng = input.lng;
const insects = input.insectList.map(id => ({ id })) as Insect[];
coordinate.insects = Promise.resolve(insects);
const response = await this.coordinateRepo.save(coordinate);
return response;
}
#Authorized('ADMIN')
#Mutation(() => [Coordinate])
async createCoordinateMultiple(
#Arg('coordinates', () => [CreateCoordinateInput]) coordinates: CreateCoordinateInput[]
): Promise<Coordinate[]> {
const response = await this.coordinateRepo.save(coordinates);
const data = response.map(coordinate => ({
id: coordinate.id,
lat: coordinate.lat,
lng: coordinate.lng,
title: coordinate.title,
description: coordinate.description,
sourceId: coordinate.sourceId,
image: coordinate.image,
insects: coordinate.insectList.map(id => ({
insectId: id,
coordinateId: coordinate.id,
})),
}));
console.log(data);
return response;
}
console.log(data) output;
[
{
id: 'c2f6b8f3-3d1a-4497-a492-ace7d58d217e',
lat: 36.7812360767751,
lng: 34.5795541012578,
title: 'B - konum',
description: 'B - bilgi',
sourceId: '7c94ce2d-e5a6-4a07-a272-369b3b34a61b',
image: '1.jpg',
insects: [ [Object], [Object] ]
},
{
id: 'b555f620-e9fd-4fdf-81ef-f355cb151969',
lat: 36.7819407011663,
lng: 34.580841561585,
title: 'D - konum',
description: 'D - bilgi',
sourceId: '7c94ce2d-e5a6-4a07-a272-369b3b34a61b',
image: '2.jpg',
insects: [ [Object], [Object] ]
}
]
https://github.com/typeorm/typeorm/issues/6713
I found a different solution. Although I don't know a clean use. At least it works for now while I wait for the answer from TypeORM developers.
I'm creating another entity for the coordinate and insect relationship.
I then save the coordinate assets. I match the coordinate ids from the returned answer and the insect ids that need to be written later into an array object.
#Authorized('ADMIN')
#Mutation(() => [Coordinate])
async createCoordinateMultiple(
#Arg('createCoordinateInputs', () => [CreateCoordinateInput]) inputs: CreateCoordinateInput[]
): Promise<Coordinate[]> {
const response = await this.coordinateRepo.save(inputs);
const coordinatesInsects = [];
response.forEach(coordinate => {
coordinate.insectList.forEach(insect => {
coordinatesInsects.push({ coordinateId: coordinate.id, insectId: insect })
})
});
await this.coordinateInsectRepo.save(coordinatesInsects);
return response;
}

Proxy in mobx -state-tree

I'm trying to build a simple budgeting app.
Whenever I insert this model into my app. I get a proxy for the expenses. Where is the flaw in my thinking?
I have an action on the Budget.js
when I print it in the useEffect this is what console.log outputs for the expenses a proxy.
I'm expecting it to print the actual data from the initial state.
React.useEffect(() => {
budget.addDummyData()
console.log(budget.expenses)
}, [])
[[Handler]]: Object
[[Target]]: Array(0)
[[IsRevoked]]: false
//////////////////////////////////////////////////////////////////////
//SubCategory
const SubCategory = types
.model('SubCategory', {
id: types.maybeNull(types.string, ''),
name: types.maybeNull(types.string, ''),
amount: types.maybeNull(types.number, 0)
})
const SubCategoryStore = types.model({ subCategory: types.optional(SubCategory, {}) })
export default SubCategoryStore
/////////////////////////////////////////////////////////////////////////
//Category.js
const Category = types
.model('Category', {
id: types.maybeNull(types.string, ''),
name: types.maybeNull(types.string, ''),
subCategories: types.array(SubCategory)
})
const CategoryStore = types.model({ category: types.optional(Category, {}) })
export default CategoryStore
///////////////////////////////////////////////////////////////
// Budget
const Budget = types
.model('Budget', {
totalIncome: 200,
expenses: types.array(Category)
// incomes: types.optional(types.array(Category), [])
}).actions({
addDummyData() {
self.expenses.push(initialStateExpenses)
}
})
const BudgetStore = types.model({ budget: types.optional(Budget, {}) })
export default BudgetStore
const initialStateExpenses = {
id: '123',
name: 'Food',
subCategories: [
{
id: '1314',
name: 'Grocery',
amount: 250
},
{
id: '1442',
name: 'Restaurants',
amount: 50
}
]
}
expenses is of type Category[], you are passing an object. I assume you want to set the expenses from subCategories. If so you can try this
addDummyData() {
initialStateExpenses.subCategories.forEach(ex => self.expenses.push(ex))
}
or
addDummyData() {
self.expenses = initialStateExpenses.subCategories
}
A better approach would be to pass the initialStateExpenses via args to the addDummyData function so your model doesn't depend on external variables
addDummyData(initialStateExpenses) {
initialStateExpenses.subCategories.forEach(ex => self.expenses.push(ex))
}
or
addDummyData(initialStateExpenses) {
self.expenses = initialStateExpenses.subCategories
}
then use it like
budget.addDummyData(initialStateExpenses)

Categories