Module exports async function undefined can't await - javascript

So, as far as I google it, I understood that this problem relevant to async / promise coding. I waste over 2Hr plus with this, but still receive no result. Probably because I'm bad in it. So my identifier.js code is right and works fine, it returns the exact data I want. app.js is still good too. So where is the problem? I can't export result value from identifier.js, because if I do it, I receive 'undefined':
const identifier = require("./db/ops/identifier");
trade_log.create({
Flag: req.body.Flag,
Instrument: req.body.Instrument,
Venue: req.body.Venue,
Price: req.body.Price,
Currency: req.body.Currency,
Quantity: req.body.Quantity,
Counterparty: req.body.Counterparty,
Identifier: identifier(req.body.Counterparty),
Commentary: req.body.Commentary,
but if I export it correcty (according to other guides), just like
let x = identifier(req.body.Counterparty).then(return value);
I receive an error at writing trade_log.create phase.
What is identifier.js? This module is a function that should request data from input form (req.body) via get and receive responce, return data & then in app.js it should be written in to MongoDB (writing works fine, already tested it)
app.js
const trade_log = require("./db/models/trade_log");
const identifier = require("./db/ops/identifier");
app.all('/log', function (req, res, next) {
let x = identifier(req.body.Counterparty.then();
trade_log.create({
Flag: req.body.Flag,
Instrument: req.body.Instrument,
Venue: req.body.Venue,
Price: req.body.Price,
Currency: req.body.Currency,
Quantity: req.body.Quantity,
Counterparty: req.body.Counterparty,
Identifier: x,
Commentary: req.body.Commentary,
},function (err, res) {
if (err) return console.log (req.body) + handleError(err);
console.log(res);
});
next();
});
identifier.js:
const identifier = (name) => {
request(['options, name'], { 'whatever' })
.then(response => {
/code that works fine
let charset = result;
return (charset);
module.exports = identifier;
I already tried in Identifier.js this export methods:
function name(param) {
//code here
}
module.exports = name();
and this:
module.exports = {
function: (name) => {
//code here
}
I also find relevant this SW answer: Asynchronous nodejs module exports but I still can't understand what am I doing wrong.
How should I correct my code accrding to new ES6 standard or should I use another module.exports method?

Related

MongooseError: Query was already executed:

I'm trying to update the document but the error says the query has already been executed.
MongooseError: Query was already executed: footballs.updateOne({ date: 'January 4' }, {})
app.post('/api/bookslot', async (req, res) => {
console.log(req.body);
try {
const token = req.headers['x-access-token'];
const decoded = jwt.verify(token, 'secret123');
const email = decoded.email;
const user = await UserModel.findOne({ email: email });
let sportname = req.body.selectedSport.toLowerCase();
const time = req.body.slotTime;
const seats = req.body.availableSeats - 1;
if (!sportname.endsWith('s')) {
sportname = sportname.concat('s');
}
const NewSlotModel = mongoose.model(sportname, slotSchema);
var update = {};
update[time] = seats - 1;
console.log(update);
const a = await NewSlotModel.updateOne(
{ date: req.body.slotDate },
{ $set: update },
function (err, success) {
if (err) return handleError(err);
}
);
return res.json({ status: 'ok' });
} catch (e) {
console.log(e);
res.json({ status: 'error' });
}
});
where am I going wrong?
You are using both async/await and callbacks in your code, causing mongoose to throw an error.
The actual effect of using them both is exactly the error type that you are receiving:
Query was already executed
Mongoose v6 does not allow duplicate queries.
Mongoose no longer allows executing the same query object twice. If
you do, you'll get a Query was already executed error. Executing the
same query instance twice is typically indicative of mixing callbacks
and promises, but if you need to execute the same query twice, you can
call Query#clone() to clone the query and re-execute it. See gh-7398
Duplicate Query Execution
To fix the issue, just remove the third argument from the await
NewSlotModel.updateOne
Making it:
const a = await NewSlotModel.updateOne(
{ date: req.body.slotDate },
{ $set: update }
);
Mongoose v6. Don't support callbacks any longer.. check the image.
const productCount = await Product.countDocuments((count) => count) BAD
const productCount = await Product.countDocuments(); GOOD

Unable to export db properties from nodejs module

I am trying to export database properties stored in properties file from Javascript module. By the time I read database properties file, Javascript file is already exported and data properties appear undefined wherever I use in other modules.
const Pool = require('pg').Pool;
const fs = require('fs')
const path = require('path');
class DbConfig {
constructor(dbData) {
this.pool = new Pool({
user: dbData['user'],
host: dbData['host'],
database: dbData['database'],
password: dbData['password'],
max: 20,
port: 5432
});
}
}
function getdbconf() {
const dbData = {};
fs.readFile("../../db_properties.txt"), 'utf8', (err, data) => {
if (err) {
console.error(err)
return
}
// dbData = {"user":"postgres", "password": "1234"...};
return dbData;
});
}
let db = new DbConfig(getdbconf());
let dbPool = db.pool;
console.log("dbpool : -> : ",dbPool); // username and password appear undefined
module.exports = { dbPool };
Is there a way to read data before exporting data from Javascript module?
Usually database config or any other sensitive info is read from a .env file using dotenv .
Or
you could also provide env from command line itself like
DB_HOST=127.0.0.1 node index.js
inside your index.js
console.log(process.env.DB_HOST)
Please create a new file (connection-pool.js) and paste this code:
const { Pool } = require('pg');
const poolConnection = new Pool({
user: 'postgresUserName',
host: 'yourHost',
database: 'someNameDataBase',
password: 'postgresUserPassword',
port: 5432,
});
console.log('connectionOptions', poolConnection.options);
module.exports = poolConnection;
For use it, create a new file (demo-connection.js) and paste this code:
const pool = require('./connection-pool');
pool.query('SELECT NOW();', (err, res) => {
if (err) {
// throw err;
console.log('connection error');
return;
}
if (res) {
console.log(res.rows);
pool.end();
}
});
This is an alternative option 🙂
Exporting the result of async calls
To export values which have been obtained asynchronously, export a Promise.
const fs = require('fs/promises'); // `/promise` means no callbacks, Promise returned
const dbDataPromise = fs.readFile('fileToRead')); //`readFile` returns Promise now
module.exports = dbDataPromise;
Importing
When you need to use the value,
const dbDataPromise = require('./dbdata');
async init() {
const dbData = await dbDataPromise;
}
//or without async, using Promise callbacks
init() {
dbDataPromise
.then(dbData => the rest of your code that depends on dbData here);
}
Current code broken
Please note that your current code, as pasted above, is broken:
function getdbconf() {
const dbData = {};
fs.readFile("../../db_properties.txt"), 'utf8', (err, data) => {
//[...] snipped for brevity
return dbData;
});
}
fs.readFile "returns" dbData, but there is nothing to return to, since you are in a callback which you did not call yourself. Function getdbconf returns nothing.
The line that says let db = new DbConfig(getdbconf()); will NOT work. It needs to be inside the callback.
The only way to avoid putting all of your code inside the callback (and "flatten" it) is to use await, or to use readFileSync
Avoiding the issue
Using environment variables
Suhas Nama's suggestion is a good one, and is common practice. Try putting the values you need in environment variables.
Using synchronous readFile
While using synchronous calls does block the event loop, it's ok to do during initialization, before your app is up and running.
This avoids the problem of having everything in a callback or having to export Promises, and is often the best solution.

how to reference a currency collection from within a module in nodejs

I'm attempting to make an economy discord bot using node.js and I'm trying to move the commands into modules so that I can have a generic/dynamic command handler. How do I reference the currency collection and the models that I created within the main file within the command modules?
index.js file:
const currency = new Discord.Collection();
//defining methods for the currency collection
Reflect.defineProperty(currency, 'add', {
/* eslint-disable-next-line func-name-matching */
value: async function add(id, amount) {
const user = currency.get(id);
if (user) {
user.balance += Number(amount);
return user.save();
}
const newUser = await Users.create({ user_id: id, balance: amount });
currency.set(id, newUser);
return newUser;
},
});
Reflect.defineProperty(currency, 'getBalance', {
/* eslint-disable-next-line func-name-matching */
value: function getBalance(id) {
const user = currency.get(id);
return user ? user.balance : 0;
},
});
(In a subfolder) balance.js:
module.exports = {
name: 'balance',
description: 'get balance',
execute(message, args) {
const target = message.mentions.users.first() || message.author;
return message.channel.send(`${target.tag} has ${currency.getBalance(target.id)}🍉`);
},
};
Which currently throws an error on currency, since it's not defined. However, I don't know how to reference the currency collection I made in index.js, which also has methods created for it.
Thank you in advance.
To do this you could attach the Collection to your Client. Something like
Client.currency = new Discord.Collection()
Every time you then reference the collection, instead of doing currency you would then run Client.currency.
As for accessing the currency object across the files, I'd add another parameter to your execute method, something like this:
module.exports = {
name: 'balance',
description: 'get balance',
execute(client, message, args) { // Notice the added "client"
const target = message.mentions.users.first() || message.author;
return message.channel.send(`${target.tag} has ${client.currency.getBalance(target.id)}🍉`); // Added "client." in front of "currency", because currency is a property of your client now
},
};
Then, when executing the execute method, you'd run execute(Client, message, arguments);. Your client would then be passed into the command and be usable in there.

Issues with scope in try/catch while using async/await

My issue is that (seemingly) things are going out of scope, or the scope is being polluted when I enter my catch block in the function below:
export const getOne = model => async (req, res, next) => {
let id = req.params.id
let userId = req.user
try {
let item = await model.findOne({ _id: id, createdBy: userId }).exec()
if (!item) {
throw new Error('Item not found!')
} else {
res.status(200).json({ data: item }) // works perfectly
}
} catch (e) {
res.status(400).json({ error: e }) // TypeError: res.status(...).json is not a function
// also TypeError: next is not a function
// next(e)
}
}
Interestingly enough, using res.status(...).end() in the catch block works just fine, but it bothers me that I am not able to send any detail back with the response. According to the Express Documentation for res.send() and res.json I should be able to chain off of .status(), which, also interestingly enough, works just fine in the try statement above if things are successful - res.status(200).json(...) works perfectly.
Also, I tried abstracting the error handling to middleware, as suggested on the Express documentation, and through closures, I should still have access to next in the catch statement, right? Why is that coming back as not a function?
Why does res.status(...).json(...) work in my try but not catch block?
Why is next no longer a function in the catch block?
Thanks in advance!
Edit
This is failing in unit tests, the following code produces the errors described above:
describe('getOne', async () => {
// this test passes
test('finds by authenticated user and id', async () => {
expect.assertions(2)
const user = mongoose.Types.ObjectId()
const list = await List.create({ name: 'list', createdBy: user })
const req = {
params: {
id: list._id
},
user: {
_id: user
}
}
const res = {
status(status) {
expect(status).toBe(200)
return this
},
json(result) {
expect(result.data._id.toString()).toBe(list._id.toString())
}
}
await getOne(List)(req, res)
})
// this test fails
test('400 if no doc was found', async () => {
expect.assertions(2)
const user = mongoose.Types.ObjectId()
const req = {
params: {
id: mongoose.Types.ObjectId()
},
user: {
_id: user
}
}
const res = {
status(status) {
expect(status).toBe(400)
return this
},
end() {
expect(true).toBe(true)
}
}
await getOne(List)(req, res)
})
})
Why does res.status(...).json(...) work in my try but not catch block?
Seems like you're passing a non-express object that only has status & end methods when running using the unit testing. That's why it fails to find the json method

TypeError: usert.addItem is not a function

Trying to make a discord bot using discord.js. I'm using sequelize and sqlite to create a database to store data. A custom function doesn't seem to work, the terminal thinks it's not a function when actually defined. There could be a really obvious solution to this, but I'm very amateur, and I get errors often, but usually fix them. This one I can't even determine the root of the problem
This problem also applies to other custom functions
The most confusing bit is that, for another folder for another bot entirely, with very similar code and essentially the same custom functions, it works! But for some reason, it doesn't work here.
// Defining these
const { Users, ItemDB } = require('./dbObjects');
// The command that uses the function. It is worth noting that it finds the item and user successfully, proving that the problem is in users.addItem
const item = await ItemDB.findByPk(1);
const usert = Users.findByPk(message.author.id);
usert.addItem(item);
// The addItem function defined, in dbObjects file
Users.prototype.addItem = async function(item) {
const useritem = await UserItems.findOne({
where: { user_id: this.user_id, item_id: item.id },
});
if (useritem) {
useritem.amount += 1;
return useritem.save();
}
return UserItems.create({ user_id: this.user_id, item_id: item.id, amount: 1 });
};
The expected result is successfully adding to the database, but instead the terminal returns:
(node:21400) UnhandledPromiseRejectionWarning: TypeError: usert.addItem is not a function
Adding await before Users.findByPk returns as random.
You need to await Users.findByPk(message.author.id);
const { Users, ItemDB } = require('./dbObjects');
// The command that uses the function. It is worth noting that it finds the item and user successfully, proving that the problem is in users.addItem
const item = await ItemDB.findByPk(1);
const usert = await Users.findByPk(message.author.id);
usert.addItem(item);
// The addItem function defined, in dbObjects file
Users.prototype.addItem = async function(item) {
const useritem = await UserItems.findOne({
where: { user_id: this.user_id, item_id: item.id },
});
if (useritem) {
useritem.amount += 1;
return useritem.save();
}
return UserItems.create({ user_id: this.user_id, item_id: item.id, amount: 1 });
Since Users.findByPk(message.author.id) is a promise it returns execution to the next sequence code, so therefore the variable const usert is not yet initialized which results in usert.addItem() not being function.
You need to change const usert = Users.findByPk(message.author.id) to this for usert to be fully initialized, the addItem() function will be available then:
const usert = await Users.findByPk(message.author.id);

Categories

Resources