Calling a method within a dynamically named object - node.js

I am trying to invoke a method of a dynamically named object.
I have a few objects each containing a method named 'getWeight'. I need to invoke this method of a subset of these objects. However, the subset of objects depends on user inputted info, which is why I'm attempting to dynamically construct the object name and invoke it's 'getWeight' method within a loop.
My code is below:
// Importing objects containing 'getWeight' method
const Apple = require('../classses/Apple');
const Pear = require('../classes/Pear);
const Carrot = require('../classes/Carrot);
const Potato = require('../classes/Potato);
const promises = {};
const user = 'userX'; // This is the inputted info, could also equal 'userY'.
const searchableFoods = {
userX: ['Apple', 'Pear'],
userY: ['Carrot', 'Potato']
};
for (i = 0; i < searchableFoods[user].length; ++i) {
promises[searchableFoods[user][i]] = new Promise(function(resolve, reject) {
// Below line should behave like: Apple.getWeight(arg1, function....
searchableFoods[user][i].getWeight(arg1, function(response) {
resolve(response);
})
})
}
Unfortunately, I get this error:
[searchableFoods[user][i].getweight] is not a function
I've tried a number of variations but can't make it work. Is it possible to do this?

Require all of those into a single object rather than many standalone variables, and then you can use simple property lookup to get to the appropriate requireed value. Also, forEach will likely result in more readable code, and you can pass the function name alone (resolve) rather than defining an extra anonymous function for the getWeight callback:
const foods = {
Apple: require('../classses/Apple'),
Pear: require('../classes/Pear),
Carrot: require('../classes/Carrot),
Potato: require('../classes/Potato)
};
// ...
searchableFoods[user].forEach((foodName) => {
promises[foodName] = new Promise((resolve) => {
foods[foodName].getWeight(arg1, resolve);
});
});

Can you define array not using strings? Something like that?
const searchableFoods = {
userX: [Apple, Pear],
userY: [Carrot, Potato]
};

You're trying to access getWeight as a property of string 'Apple' and not of the actual object Apple that you are importing.
Change the subset array to something like this
const searchableFoods = {
userX: [Apple, Pear],
userY: [Carrot, Potato]
};
Which makes the final code to be
const Apple = require('../classses/Apple');
const Pear = require('../classes/Pear);
const Carrot = require('../classes/Carrot);
const Potato = require('../classes/Potato);
const promises = {};
const user = 'userX' // This is the inputted info, could also equal 'userY'.
const searchableFoods = {
userX: [Apple, Pear],
userY: [Carrot, Potato]
};
for (i = 0; i < searchableFoods[user].length; ++i) {
promises[searchableFoods[user][i]] = new Promise(function(resolve, reject) {
// Below line should behave like: Apple.getWeight(arg1, function....
searchableFoods[user][i].getWeight(arg1, function(response) {
resolve(response);
})
})
}

Related

NodeJS/MongoDB function returning array with wrong data

so I have a collection where I will have a lot of documents, but for now lets suppose it has about 100. (It had less than that when I was testing).
So, I need to get all the documents of the collection, put in a array, sort that and then send it to the websocket for the frontend. But the array is going with wrong data.
This is my code:
const emitSales = async (socket) => {
let salesArray = [];
const saleExists = (contract) => {
return salesArray.some(element => element.contract === contract);
}
const addSale = (contract) => {
const element = salesArray.find(e => e.contract === contract);
element.sales = element.sales+1;
}
const sales = await fiveMinSchema.find({}).lean();
if(sales) {
for await (x of sales) {
if(saleExists(x.contract)) {
addSale(x.contract);
continue;
}
const collection = await Collection.findOne({
contract: x.contract
});
let newsale = {
contract: x.contract,
title: collection.title,
description: collection.description,
image: collection.image,
sales: 1,
}
salesArray.push(newsale);
}
socket.emit("5min", salesArray.sort((a,b) => {
return b.sales-a.sales;
}).slice(0,10));
}
}
So, when I execute this function only once, for example, the array returns the correct values. But if I execute the function like 2 times in a row (like very fast), it starts returning the array with wrong data. (like mixing the data).
And as I using websocket, this function will execute like every 2 seconds (for example). How can I fix this problem? Like it seems to be executing more than one time simultaneously and mixing the data, idk..

How can I store the value of a promise and use it once resolved?

I am currently developing an app which interacts with uniswap, and I have developed a Wrapper class to contain the info and variables I'll need about some pair (e.g DAI/WETH).
As some of this values are asynchronous, I have coded a build() async function to get those before calling the constructor, so I can store them. I want to store the result of this build function, which is an instance of the class I have defined, inside a variable to use it later, but I need to know whether the Promise that that build function returns is resolved before using it, so how can I make it?
Here is the code of the class:
'use strict'
const { ChainId, Fetcher, WETH, Route, Trade, TokenAmoun, TradeType, TokenAmount } = require('#uniswap/sdk')
const { toChecksumAddress } = require('ethereum-checksum-address')
const Web3 = require('web3')
const web3 = new Web3()
const chainId = ChainId.MAINNET;
let tok1;
let tok2;
let pair;
let route;
let trade;
class UniswapTokenPriceFetcher
{
constructor(async_params)
{
async_params.forEach((element) => {
if (element === 'undefined')
{
throw new Error('All parameters must be defined')
}
});
this.trade = async_params[0];
this.route = async_params[1];
this.pair = async_params[2];
this.tok1 = async_params[3];
this.tok2 = async_params[4];
}
static async build(token1, token2)
{
var tok1 = await Fetcher.fetchTokenData(chainId, toChecksumAddress(token1))
var tok2 = await Fetcher.fetchTokenData(chainId, toChecksumAddress(token2))
var pair = await Fetcher.fetchPairData(tok1, tok2)
var route = new Route([pair], tok2)
var trade = new Trade(route, new TokenAmount(tok2, web3.utils.toWei('1', 'Ether')), TradeType.EXACT_INPUT)
return new UniswapTokenPriceFetcher([trade, route, pair, tok1, tok2])
}
getExecutionPrice6d = () =>
{
return this.trade.executionPrice.toSignificant(6);
}
getNextMidPrice6d = () =>
{
return this.trade.nextMidPrice.toSignificant(6);
}
}
module.exports = UniswapTokenPriceFetcher
Thank you everybody!
EDIT: I know Uniswap only pairs with WETH so one of my token variables is unneccesary, but the problem remains the same! Also keep in mind that I want to store an instance of this class for latter use inside another file.
You should either call the build function with await
const priceFetcher = await UniswapTokenPriceFetcher.build(token1, token2)
or followed by then
UniswapTokenPriceFetcher.build(token1, token2).then(priceFetcher => {...})
I don't see any other way.

node.js - Use variables outside functions

I'm new to node.js, and I'm struggling with functions and variables.
let shops = ['shop-one', 'shop-two']
function getShops(shops){
shops.forEach(element => {
console.log(element)
const shop = element
});
}
function getUrl(shop){
console.log(shop)
}
getShops(shops)
getUrl(shop) // shop is not defined
How can I use variables from one function on the other function or outside the functions for further use?
Like in my example I would use the Shopname 'shop-one' from the forEach-Loop in function getShops to be used on the function getUrl or even outside any function.
I would be grateful for any help.
let shops = ['shop-one', 'shop-two'];
// An object to store urls that will look like
// {'shop-one': 'http://aurl4shop1.com', 'shop-two': 'http://aurl4shop2.com' }
let urls = {};
let json = [];
function getShops(shops){
shops.forEach(element => {
console.log(element);
const shop = element;
// The following line will set a property on the url object with the value of the url. The property name is the shop name.
url[shop] = getUrl(shop);
});
}
function getUrl(shop){
console.log(shop);
}
shops.forEach(shop => json[shop] = fetchJson(shop);
// At this point the json object should look like this:
// { 'shop-one': { /* some json */ }, 'shop-two': /* some json */ }

nodejs discord get nickname from a users ID

My goals are to obtain the users nickname by using their ID.
Their ID's are stored as variables which are being collected from a reaction collector.
I have tried a few methods and failed, most of which either return nothing or errors.
The below code returns nothing, the getnames() function is empty. This method was recommended to me buy 2 people from a nodejs discord server which aims to help solve issues, similar to here.
// returns player ID's
function getPlayers() {
let players = [];
players.push(queue.tank[0]); // First (1) in TANK queue
players.push(queue.heal[0]); // First (1) in HEAL queue
players.push(queue.dps[0]); // First (2) in DPS queue
players.push(queue.dps[1]);
return players;
}
// get nick names from ID's
function getnames() {
let players = getPlayers();
let playerNicks = [];
let newPlayer = "";
players.forEach(async player => {
newPlayer = await message.guild.members.fetch(player).then(function (user) {return user.displayName });
playerNicks.push(newPlayer)
return playerNicks;
})}
//formats nicknames into string
function formatnicknames() {
let formatted_string2 = '';
let playerNicks = getnames();
if (playerNicks)
formatted_string2 = `${playerNicks[0]} \n${playerNicks[1]} \n${playerNicks[2]} \n${playerNicks[3]}`;
return formatted_string2;
}
I have also tried a few variations of the below code, still unable to obtain nickname.
message.guild.members.cache.get(user.id)
Edit #1
now tried the following code with no success. (boost1ID contains the ID of 1 user)
var mem1 = message.guild.members.fetch(boost1ID).nickname
Edit #2
tried a new method of obtaining displayname from ID.
var guild = client.guilds.cache.get('guildid');
var mem1 = guild.member(boost1ID);
var mem2 = guild.member(boost2ID);
var mem3 = guild.member(boost3ID);
var mem4 = guild.member(boost4ID);
var nickname1 = mem1 ? mem1.displayName : null;
var nickname2 = mem2 ? mem2.displayName : null;
var nickname3 = mem3 ? mem3.displayName : null;
var nickname4 = mem4 ? mem4.displayName : null;
var Allnicknames = `${nickname1} ${nickname2} ${nickname3} ${nickname4}`
message.channel.send(`testing nicknames: ${Allnicknames}`)
I managed to only return my own name since i dont have a nickname on this server, but the other three users who does have a nickname returned null.
This is the simplest solution:
// your users ids
const IDs = [ '84847448498748974', '48477847847844' ];
const promises = IDs.map((userID) => {
return new Promise(async (resolve) => {
const member = message.guild.member(userID) || await message.guild.members.fetch(userID);
resolve(member.displayName || member.user.username);
});
});
const nicknames = await Promise.all(promises);
// you now have access to ALL the nicknames, even if the members were not cached!
The members you are trying to get the nicknames of are not necessarily cached, and this fixes that.
I made an example that could help you.
let testUsers = [];
module.exports = class extends Command {
constructor(...args) {
super(...args, {
description: 'Testing.',
category: "Information",
});
}
async run(message) {
function getNicknames(userArr, guild) {
let playerNicks = [];
for(var i = 0; i < userArr.length; i++) {
playerNicks.push(guild.member(userArr[i]).displayName);
}
return playerNicks;
}
let testUser = message.guild.members.cache.get(message.author.id);
testUsers.push(testUser);
let guild = message.guild;
console.log(getNicknames(testUsers, guild));
}
}
I created a function getNicknames that takes in two parameters. The first one is an Array of users (as you get one from your function getPlayers()) and the second one is the guild you are playing in. You need to provide the guild, because every user should be a GuildMember, because you want to use .displayName. I created a user Array outside of my command code, because otherwise there will only be one user in the Array everytime you use the command. Inside of the getNicknames() function I have created a new Array playerNicks that I basically fill with the user nicknames we get from our provided user Array.
Now you have to implement that into your code.
The call of the function getNicknames(), for your code should look like this:
getNicknames(getPlayers(), message.guild);

How do I chain a set of functions together using promises and q in node.js?

I have some dynamic data that needs to have work performed on it. The work must happen sequentially. Using the Q Library, I'd like to create an array of functions and execute the code sequentially using sequences. I can't seem to quite figure out the syntax to achieve this.
const fruits = ["apple", "cherry", "blueberry"]
function makeFruitPie (fruit) {
return Q.Promise((resolve, reject) => {
// Do some stuff here
resolve(fruit+" pie")
// Error handling here
reject(new Error(""))
})
}
const fruitFuncs = new Array(fruits.length)
for(var i = 0; i < fruits.length; i++) {
fruitFuncs[i] = makeFruitPie(fruits[i])
}
// Stole this example from the github docs but can't quite get it right.
i = 0
var result = Q(fruits[i++])
fruitFuncs.forEach((f) => {
result = result(fruits[i++]).then(f)
})
With these lines
for(var i = 0; i < fruits.length; i++) {
fruitFuncs[i] = makeFruitPie(fruits[i])
}
you already run the functions and, hence, their processing will begin.
Assuming you want the execution of the functions in sequence, the following would be more appropriate:
// construct the pipeline
const start = Q.defer();
let result = start.promise; // we need something to set the pipeline off
fruits.forEach( (fruit) => {
result = result.then( () => makeFruitPie( fruit ) );
});
// start the pipeline
start.resolve();
Sidenote: There is a native Promise implementation supported by almost all environments. Maybe consider switching from the library backed version.
You can use Promise.all
Promise.all(fruits.map(fruit=>makeFruitPie(fruit).then(res=> res) )).
then(final_res => console.log(final_res))
final_res will give you array of results
you could use for..of and do things sequentially. something like this
const Q = require("q");
const fruits = ["apple", "cherry", "blueberry"];
function makeFruitPie(fruit) {
return Q.Promise((resolve, reject) => {
// Do some stuff here
resolve(`${fruit} pie`);
// Error handling here
reject(new Error(""));
});
}
for (const fruit of fruits) {
const result = await makeFruitPie(fruit);
console.log(result);
}
By the way also worth considering native Promise insteead of using q

Resources