Node Discord.js Axios API Indexing - node.js

I want to index through a list of items stored in a json file and call to each API and bring back data. The below code shows indexing/map working by building an API link, but how do I get the whole API call and message to be inside the indexing so each list item is called and returned by the API:
// {"342671641006047252":["MSFT","AMZN","CVNA","TEAM"]}
console.log(list);
// This is indexing through the list and bulding the link
const tickers = list
.map((ticker, index) => `https://financialmodelingprep.com/api/v3/quote/${ticker}?apikey=6c7ee1f3c7a666228979fa0678fa22a3`)
return message.channel.send(tickers)
// This is going to the api for list[0]
axios.get('https://financialmodelingprep.com/api/v3/quote/'+list[0]+'?apikey=6c7ee1f3c7a666228979fa0678fa22a3').then(resp => {
console.log(resp.data);
let symbol = resp.data[0].symbol;
let price = resp.data[0].price;
let changesPercentage = resp.data[0].changesPercentage;
return message.channel.send({embed: {
color: 8311585,
fields: [{
name: "Ticker",
value: `${symbol}`,
inline: "true"
},
{
name: "Price",
value: `${price}`,
inline: "true"
},
{
name: "Change %",
value: `${changesPercentage}`,
inline: "true"
},

Nevermind on this one! I used forEach instead of .map and got it working!

Related

Displaying the correct image when pokemon is called

I am having issues posting an image of a Pokémon when command is used
const { Message, Client, MessageEmbed, MessageAttachment } = require("discord.js");
const {Ecolor} = require("../../embeds.js")
pokemon = require('../../db/pokemon.js')
module.exports = {
name: "pokeinfo",
description: "Shares Information about specified Pokemon of the game",
run: async (client, message, args) => {
let pkmn = message.content.toLowerCase().split("!pokeinfo ")[1]
for(var i=0;i<pokemon.length;i++){
if(pkmn == pokemon[i]._engName.toLowerCase()){
let Embed = new MessageEmbed()
.setColor(`${Ecolor.pink}`)
.setTitle(`Details about ${pokemon[i]._engName} :`)
.setDescription(`Dex number - ${pokemon[i]._nb}`)
.setThumbnail('https://imgur.com/Q6WZOoU.png')//https://imgur.com/Q6WZOoU.png
.addFields(
{name: 'Rarity:', value:`${pokemon[i]._rare}`, inline: true },
{name: 'Evolution Chart:', value:`${pokemon[i]._evo}`, inline: true },
{name: 'Location:', value:`${pokemon[i]._loc}`, inline: false },
{name: 'Ev Yield:', value:`${pokemon[i]._ev}`, inline: true },
{name: 'Ability:', value:`${pokemon[i]._ability}`, inline: true },
{name: '__Base Stats__:', value:
`
**HP** : ${pokemon[i]._baseStats._hp}
**Atk** : ${pokemon[i]._baseStats._atk}
**Def** : ${pokemon[i]._baseStats._def}
**S. Atk** : ${pokemon[i]._baseStats._sAtk}
**S. Def** : ${pokemon[i]._baseStats._sDef}
**Speed** : ${pokemon[i]._baseStats._spd}
**Total** : ${pokemon[i]._baseStats._total}
**Growth Rate** : ${pokemon[i]._gr}
**Type** : ${pokemon[i]._ty}
`, inline: false },
);
message.channel.send({ embeds: [Embed] });
}
}
},
};
if simplisty were just gonna use 1 pokemon below is the info being called
{
_nb:1,_engName:"Bulbasaur",_rare:"N/A",
_evo:"Bulbasaur lvl 16 | Ivysaur lvl 36 | Venusaur | Mega",
_loc:"Starter ",
_ev:"1 SpA",
_ability:"Overgrow, *Chlorophyll(HA)",
_baseStats: {_total:318,_hp:45, _atk:49, _def:49, _sAtk:65, _sDef:65, _spd:45},
_gr:"Medium Slow",_ty:"Grass/Poison"
_pho: "bulbasaur.png"
i have changed .setThumbnail('https://www.pokemon.com/us/pokedex/' + ${pokemon[i]._pho}) and in the second file added _pho: bulbasaur.png
as when that is all together is will take you to https://www.pokemon.com/us/pokedex/bulbasaur.png.
I'm just trying to set a thumbnail to display the Pokémon that is being searched for. and I'm not able to figure it out.
when I use the pokemon.com..... and hover over the image after I call the command it displays the link but not the image, if click on the thumbnail image (which is a pile of poo) it will take me to the correct page, but again the image on the bot command is not showing.
If you are looking to display the Pokémon in the Thumbnail, the URL you should give is the URL that takes you to the image and not the URL where you see the Pokémon information.
The direct URL of the image can be obtained by right clicking -> Copy address/image link.
In the case of Bulbasaur, the URL of its image is: https://assets.pokemon.com/assets/cms2/img/pokedex/full/001.png and not https://www.pokemon.com/us/pokedex/bulbasaur.png
A quick and probably functional solution would be to dynamically obtain the URL of the Pokémon images according to their number in the pokedex, as it seems that in the assets they are stored/differentiated by number and not by names.
.setThumbnail(`https://assets.pokemon.com/assets/cms2/img/pokedex/full/${pokemon[i]._nb}.png`)

SNS SDK for NodeJS won't create FIFO topic

When I create a topic using the sns.createTopic (like the code below) it won't accept the booleans and say 'InvalidParameterType: Expected params.Attributes['FifoTopic'] to be a string', even though the docs say to provide boolean value, and when I provide it with a string of 'true' it still doesn't set the topic type to be FIFO, anyone knows why?
Here's the code:
const TOPIC = {
Name: 'test.fifo',
Attributes: {
FifoTopic: true,
ContentBasedDeduplication: true
},
Tags: [{
Key: 'test-key',
Value: 'test-value'
}]
};
sns.createTopic(TOPIC).promise().then(console.log);
Used aws-sdk V2
I sent FifoTopic and ContentBasedDeduplication as strings.
The below code works fine for me
const TOPIC = {
Name: 'test.fifo',
Attributes: {
FifoTopic: "true",
ContentBasedDeduplication: "true"
},
Tags: [{
Key: 'test-key',
Value: 'test-value'
}]
};
let sns = new AWS.SNS();
let response3 =await sns.createTopic(TOPIC).promise();
console.log(response3);
Note: Make sure your lambda has correct permissions.
You will be getting attributes like FifoTopic and ContentBasedDeduplication when performing the getTopicAttributes.
let respo = await sns.getTopicAttributes({
TopicArn:"arn:aws:sns:us-east-1:XXXXXXX:test.fifo"}
).promise();
please find the screenshot

knex js query many to many

i'm having trouble with node & knex.js
I'm trying to build a mini blog, with posts & adding functionality to add multiple tags to post
I have a POST model with following properties:
id SERIAL PRIMARY KEY NOT NULL,
name TEXT,
Second I have Tags model that is used for storing tags:
id SERIAL PRIMARY KEY NOT NULL,
name TEXT
And I have many to many table: Post Tags that references post & tags:
id SERIAL PRIMARY KEY NOT NULL,
post_id INTEGER NOT NULL REFERENCES posts ON DELETE CASCADE,
tag_id INTEGER NOT NULL REFERENCES tags ON DELETE CASCADE
I have managed to insert tags, and create post with tags,
But when I want to fetch Post data with Tags attached to that post I'm having a trouble
Here is a problem:
const data = await knex.select('posts.name as postName', 'tags.name as tagName'
.from('posts')
.leftJoin('post_tags', 'posts.id', 'post_tags.post_id')
.leftJoin('tags', 'tags.id', 'post_tags.tag_id')
.where('posts.id', id)
Following query returns this result:
[
{
postName: 'Post 1',
tagName: 'Youtube',
},
{
postName: 'Post 1',
tagName: 'Funny',
}
]
But I want the result to be formated & returned like this:
{
postName: 'Post 1',
tagName: ['Youtube', 'Funny'],
}
Is that even possible with query or do I have to manually format data ?
One way of doing this is to use some kind of aggregate function. If you're using PostgreSQL:
const data = await knex.select('posts.name as postName', knex.raw('ARRAY_AGG (tags.name) tags'))
.from('posts')
.innerJoin('post_tags', 'posts.id', 'post_tags.post_id')
.innerJoin('tags', 'tags.id', 'post_tags.tag_id')
.where('posts.id', id)
.groupBy("postName")
.orderBy("postName")
.first();
->
{ postName: 'post1', tags: [ 'tag1', 'tag2', 'tag3' ] }
For MySQL:
const data = await knex.select('posts.name as postName', knex.raw('GROUP_CONCAT (tags.name) as tags'))
.from('posts')
.innerJoin('post_tags', 'posts.id', 'post_tags.post_id')
.innerJoin('tags', 'tags.id', 'post_tags.tag_id')
.where('posts.id', id)
.groupBy("postName")
.orderBy("postName")
.first()
.then(res => Object.assign(res, { tags: res.tags.split(',')}))
There are no arrays in MySQL, and GROUP_CONCAT will just concat all tags into a string, so we need to split them manually.
->
RowDataPacket { postName: 'post1', tags: [ 'tag1', 'tag2', 'tag3' ] }
The result is correct as that is how SQL works - it returns rows of data. SQL has no concept of returning anything other than a table (think CSV data or Excel spreadsheet).
There are some interesting things you can do with SQL that can convert the tags to strings that you concatenate together but that is not really what you want. Either way you will need to add a post-processing step.
With your current query you can simply do something like this:
function formatter (result) {
let set = {};
result.forEach(row => {
if (set[row.postName] === undefined) {
set[row.postName] = row;
set[row.postName].tagName = [set[row.postName].tagName];
}
else {
set[row.postName].tagName.push(row.tagName);
}
});
return Object.values(set);
}
// ...
query.then(formatter);
This shouldn't be slow as you're only looping through the results once.

How to sort a list on Google-Actions/Dialogflow?

I would like to know how you can sort the OptionItems in the list of Google DialogFlow. It seems that they are automatically sorted by the key of their OptionItem. I just want them displayed on the list in the order I push them in the list, so no auto-sorting would be best.
I got following code how I create an OptionItem:
const optionItems:{[key: string]: OptionItem} = {}
optionItems[outlet.outlet_id] = {
synonyms: [
outlet.outlet_id,
],
title: outletOptionItemTitleText,
description: outletOptionItemDescriptionText,
image: {
url: outletOptionItemImageUrlText,
accessibilityText: outletOptionItemImageAccessibilityTextText,
},
}
The optionItems are passed as parameter to the List Object of Google DialogFlow like below:
conv.close(showAvailabilityText,new List({
items: optionItems,
}))
Can I pass another parameter to influence the order of the list? Or anything else?

Source object access from ColumnSet

I try to split a sub-object in my recordset when importing data with initCB properties of a Column in ColumnSet.
But when I use two different init functions for two different destination names but one source I get same result.
const cs = new pgp.helpers.ColumnSet([
'id',
{ name: 'source_id', prop: 'source', init: function(obj) { return obj.value.id; } },
{ name: 'source_name', prop: 'source', init: function(obj) { return obj.value.name; } },
], { table: 'test_table' });
const data = [
{ id: 1, source: { id: 1, name: 'source1' } },
{ id: 2, source: { id: 1, name: 'source1' } },
{ id: 3, source: { id: 2, name: 'source2' } },
];
const insert = pgp.helpers.insert(data, cs);
The result is:
INSERT INTO "test_table"("id","source_id","source_name") VALUES
(1,'source1','source1'),
(2,'source1','source1'),
(3,'source2','source2')
instead of expected:
INSERT INTO "test_table"("id","source_id","source_name") VALUES
(1,1,'source1'),
(2,1,'source1'),
(3,2,'source2')
It seems like second invocation of callback function for THE SAME source field overriding result of previous invocation of ANOTHER callback function on THIS source field.
How I can avoid this?
Or there is another way of splitting a sub-object during import?
Option prop doesn't quite work that way. It is there to remap the value to a different property name, but it does not supply the direct object reference.
Instead, use property source of the column descriptor, to reference the source object. Ironically, you called the property in your data source as well, which means you will have to use source twice in your reference:
const cs = new pgp.helpers.ColumnSet([
'id',
{name: 'source_id', init: c => c.source.source.id},
{name: 'source_name', init: c => c.source.source.name}
], {table: 'test_table'});
The first source is what pg-promise API supports, while the second is your data column name :)
Also, as per documentation, the API sets source and this to the same, so if you prefer the ES5 function syntax (looks cleaner for your example), then you can do this instead:
const cs = new pgp.helpers.ColumnSet([
'id',
{ name: 'source_id', init: function() {return this.source.id;}},
{ name: 'source_name', init: function() {return this.source.name;}},
], { table: 'test_table' });
Above we have this point at the source data object.

Resources