I want to update a globally declared variable after sqlite query,
but I cant get it to work,
I have read that it might be related to asynchronous functions but I have no idea how to implement callbacks and stuff in this example,
can you guys help please. Here is the code:
const sqlite3 = require('sqlite3').verbose();
const dbPath = './src/db/db.sqlite3';
let db = new sqlite3.Database(dbPath, (err) => {
if (err) {
console.error(err.message);
}
console.log('Connected to database.');
});
let number = null;
let rowsExist = null;
db.get("select count(*) from PRICE", [], (err, row) => {
if (err) {
console.error(err.message)
}
else {
rowsExist = Object.values(row)[0];
console.log(rowExist) //this works but outside the function it doesnt get updated
}
});
// here rowExist remains the same after query
if (rowsExist === null) {
number = 1
}
else {
db.get("SELECT number FROM PRICE ORDER BY number DESC LIMIT 1", [], (err, row) => {
if (err) {
console.error(err.message)
}
else {
number = Object.values(row)[0] + 1
}
})
};
Related
I know this questions gets asked a lot and I have looked at many similar ones but haven't been able to solve it. But I wrote my code exactly as described in MDN webdocs for async/await but it's not working as expected. Basically I am trying to seed my mongo database for my express.js application.
const Activity = require('./Models/activity');
const mongoose = require('mongoose');
const faker = require('faker');
function dropDB() {
//Check if collections exist. Drop if they do.
mongoose.connect("mongodb://localhost/auth_demo", { useNewUrlParser: true , useUnifiedTopology: true });
var db = mongoose.connection;
db.once('open', (err, res) => {
mongoose.connection.db.listCollections().toArray(function (err, names) {
// console.log(names); // [{ name: 'dbname.myCollection' }]
if (names.length > 1) {
console.log("db connect");
db.dropCollection('users', (err, res) => {
if (err){
console.log(err);
}else {
console.log("DB dropped sucessfully");
}
})
}
else {
console.log("no collections to drop");
}
});
})
}
function createUsers() {
var usersAdded = new Array();
return new Promise(resolve => {
for (let i = 0; i<20; i++) {
User.register( new User(
{
username: faker.internet.userName(),
name: faker.name.firstName() + " " + faker.name.lastName(),
zipcode: faker.address.zipCode(),
friends: []
}
), faker.internet.password(), (err, user) => {
if (err){
console.log(err)
}
else {
usersAdded.push(user);
}
}
)
};
resolve(usersAdded);
});
}
async function main() {
dropDB();
let x = await createUsers();
return x;
}
const returnedVal = main();
returnedVal.then((x) => console.log(x.length));
// module.exports = main;
This is always what prints to the console:
0,
db connect,
DB dropped sucessfully,
As you can see the console.log() in main() runs before createUsers() has finished running. So the users array is still empty even though it should have 20 users.
I am creating a pie chart which shows how much disk space is available/used on my linux box. However, I am unsure how to parse the data onto a microservice url. Help will greatly be appreciated.
Here is what I have at the moment:
Router:
router.route('/linux_disk').get(disk.get_linux_disk)
Controller:
function get_linux_disk(req, res, next) {
try {
var cmd = `df ~`;
exec(cmd)
rows = [];
rows.push({"Command": cmd});
if (rows.length >= 1) {
res.status(200).json(rows);
} else {
res.status(404).end();
}
} catch (err) {
next(err);
}
}
You might try the approach below, we create a row object for each entry that the df
command creates. Once you have this you should be able to create your pie chart from this:
const { exec } = require('child_process');
const { promisify } = require('util');
const execPromise = promisify(exec);
async function get_linux_disk(req, res, next) {
try {
const result = await execPromise(`df ~`)
const lines = result.stdout.split("\n");
const keys = lines[0].split(/\s+/ig);
// Skip the header row when assigning objects..
const rows = lines.slice(1).map(line => {
// Parse each line..
const values = line.split(/\s+/ig);
return keys.reduce((o, k, index) => {
o[k] = values[index];
return o;
}, {})
});
res.status(200).json(rows);
} catch (err) {
res.status(500).send(err.message);
}
}
The resulting JSON will look a bit like so :
[
{
"Filesystem": "/dev/sda1",
"1K-blocks": "10253588",
"Used": "7971516",
"Available": "1741504",
"Use%": "83%",
"Mounted": "/"
}
]
I am using node js to get data from dynamoDB. However at the moment I am retrieving the data with the UserId. I want to retrieve the data using the secondary index that I have created, which is dateId. My dynamoDB table consists of userId, Exercises, Sets, Reps and dateId. How can I achieve that?
I already tried to add the Index-name under the table name with the dateId value but it's not working.
My dbHelper.js looks like this.
dbHelper.prototype.getExercises = (userID) => {
return new Promise((resolve, reject) => {
const params = {
TableName: tableName,
KeyConditionExpression: "#userID = :user_id",
ExpressionAttributeNames: {"#userID": "userId"},
ExpressionAttributeValues: {":user_id": userID }
}
docClient.query(params, (err, data) => {
if (err) {
console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
return reject(JSON.stringify(err, null, 2))
}
console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
resolve(data.Items)
})
});
}
My index.js looks like this
const GetExercisesIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'GetExercisesIntent';
},
async handle(handlerInput) {
const {responseBuilder } = handlerInput;
const userID = handlerInput.requestEnvelope.context.System.user.userId;
return dbHelper.getExercises(userID)
.then((data) => {
var speechText = 'Your exercises of the day are '
if (data.length == 0) {
speechText = "You do not have any favourite exercises yet, add exercise by
saving add moviename "
} else {
speechText += data.map(e => e.Exercise).join(", ")
}
return responseBuilder
.speak(speechText)
.reprompt(GENERAL_REPROMPT)
.getResponse();
})
.catch((err) => {
const speechText = "we cannot get your exercise right now. Try again!"
return responseBuilder
.speak(speechText)
.getResponse();
})
}
}
I think your function should look more like this example, based on combining AWS's documentation with your original code.
I think you'll want to supply the partition key for the Index (which I'm assuming is dateId) rather than the table's partition key.
The ProjectionExpression seems to let us specify a list of attributes to return, and I gather that you want just the Exercises attribute for each item matching the specified dateId.
dbHelper.prototype.getExercises = (dateID) => {
return new Promise((resolve, reject) => {
const
tableName = NameOfDynamoDbTable, // Must be the actual table name
indexName = NameOfDynamoDbIndex, // Must be the actual index name on that table
params = {
"TableName": tableName,
"IndexName": indexName,
"KeyConditionExpression": "#dateID = :date_id",
"ExpressionAttributeNames": {"#dateID": "dateId"},
"ExpressionAttributeValues": {":date_id": dateID },
"ProjectionExpression": "Exercises",
"ScanIndexForward": true
};
docClient.query(params, (err, data) => {
if (err) {
console.error("Can't read item. Error JSON:", JSON.stringify(err, null, 2));
return reject(JSON.stringify(err, null, 2));
}
console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
resolve(data.Items)
});
});
};
This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 4 years ago.
I am having an issue with using async/await using node v8.1. It appears my issue is that I am not returning a promise from my async functions. This is causing the flow of the program to run out of order. I thought by making a function async that the function automatically returns a promise, but that is not the case I am running into.
I expect the program below to output:
Validating xlsx file...
(text from validateParsedXlsx)
Adding users to cognito...
(text from addUsersToCognito)
Adding users to dynamodb...
(text from addUsersToDynamodb)
Instead, I get:
Validating xlsx file...
Adding users to cognito...
Adding users to dynamodb...
(text from validateParsedXlsx)
(text from addUsersToCognito)
(text from addUsersToDynamodb)
The issue seems to be pretty obvious, that validateParsedXlsx() addUsersToCognito() and addUsersToDynamodb() are not returning promises. Again, I thought that by using the async keyword, the function automatically took care of this.
Thanks for the help.
Here is my script:
const xlsx = require('xlsx');
const AWS = require('aws-sdk');
AWS.config.update({region: 'us-west-2'});
const documentClient = new AWS.DynamoDB.DocumentClient({convertEmptyValues: true});
async function main(){
if (!process.argv[2]) {
console.log('\nAbsolute filepath missing. Pass the absolute filepath in as command line argument.\n')
process.exit(1);
}
const xlsxFilePath = process.argv[2];
let parsedXlsx = [];
try {
parsedXlsx = parseXlsx(xlsxFilePath);
} catch (error) {
if(error.code === 'ENOENT') {
console.log(`\nThe file path: ${process.argv[2]} cannot be resolved\n`)
} else {
console.log(error);
}
}
console.log('\n\nValidating xlsx file...\n');
await validateParsedXlsx(parsedXlsx);
console.log('\n\nAdding users to cognito...\n');
await addUsersToCognito(parsedXlsx);
console.log('\n\nAdding users to dynamodb...\n');
await addUsersToDynamodb(parsedXlsx);
}
function parseXlsx(filePath) {
const workbook = xlsx.readFile(filePath);
const sheetNameList = workbook.SheetNames;
const parsedXlsxSheets = sheetNameList.map(function (y) {
const worksheet = workbook.Sheets[y];
const headers = {};
const data = [];
for (z in worksheet) {
if(z[0] === '!') continue;
//parse out the column, row, and value
const col = z.substring(0,1);
const row = parseInt(z.substring(1));
const value = worksheet[z].v;
//store header names
if(row == 1) {
headers[col] = value;
continue;
}
if(!data[row]) data[row] = {};
data[row][headers[col]] = value;
}
//drop those first two rows which are empty
data.shift();
data.shift();
return data;
});
return parsedXlsxSheets[0]
}
async function validateParsedXlsx(users) {
let error = false;
users.forEach(async (user, index) => {
if (!user.email) {
console.log(`User at row ${index + 2} doesn't have 'email' entry in xlsx file.`);
error = true;
}
if (!user.displayName) {
console.log(`User at row ${index + 2} doesn't have 'displayName' entry in xlsx file.`);
error = true;
}
if (!user.serviceProviderId) {
console.log(`Userat row ${index + 2} doesn't have 'displayName' entry in xlsx file.`);
error = true;
} else {
const params = {
TableName: 'service-providers',
Key: {
serviceProviderId: user.serviceProviderId
}
}
const response = await documentClient.get(params).promise();
if (!response.Item) {
console.log(`User at row ${index +2} does not have a valid serviceProviderId.`);
error = true;
} else {
console.log(`User ${user.email} is valid, assigned to service provider: ${response.Item.displayName}`);
}
}
if (error) {
console.log(`Every user in xlsx file must have these attributes, spelled correctly: email, displayName, and serviceProviderId\n\nIn addition, make sure the serviceProviderId is correct by checking the service-providers dynanomdb table.`);
process.exit(1);
}
});
}
async function addUsersToCognito(users) {
const cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider();
const results = await cognitoIdentityServiceProvider.listUserPools({MaxResults: 10}).promise();
let serviceProviderUserPoolId = '';
results.UserPools.forEach((userPool) => {
if(userPool.Name === 'service-provider-users') {
serviceProviderUserPoolId = userPool.Id;
}
});
users.forEach(async (user) => {
const params = {
UserPoolId: serviceProviderUserPoolId,
Username: user.email,
DesiredDeliveryMediums: ['EMAIL'],
TemporaryPassword: 'New_User1',
UserAttributes: [
{
Name: 'email',
Value: user.email
},
{
Name: 'custom:service_provider_id',
Value: user.serviceProviderId
}
]
}
try {
await cognitoIdentityServiceProvider.adminCreateUser(params).promise();
console.log(`Added user ${user.email} to cognito user pool`);
} catch (error) {
if (error.code === 'UsernameExistsException') {
console.log(`Username: ${user.email} already exists. No action taken.`);
}
else {
console.log(error);
}
}
});
}
async function addUsersToDynamodb(users) {
users.forEach(async (user) => {
const params = {
TableName: 'service-provider-users',
Item: {
serviceProviderId: user.serviceProviderId,
userId: user.email,
displayName: user.displayName,
isActive: false,
role: 'BASIC'
},
ConditionExpression: 'attribute_not_exists(userId)'
}
try {
await documentClient.put(params).promise();
console.log(`Added user ${user.email} to dynamodb user table`);
} catch (error) {
if (error.code === 'ConditionalCheckFailedException') {
console.log(`User ${user.email} already in the dynamodb table service-provider-users`);
} else {
console.log(error);
}
}
});
}
main();
users.forEach(async (user, index) => {
That starts a few promising actions but never awaits them. May do:
await Promise.all(users.map(async (user, index) => {
... to execute them in parallel or do this:
await users.reduce((chain, user, index) => async (user, index) => {
await chain;
//...
}, Promise.resolve());
To execute them one after another.
PS: Using process.exit should be the very last option to end your program
I can't seem to make multiple requests from one connection to the database. It always tells me that requests can only be made from logged in state.
For example as seen in the code below: the getCarIdandOwner part of the function will fire fine. However the getChargeRate will not.
I tried combining them like so:
connection.execSqlBatch(getcarIdandOwner, getChargeRate);
However that did not work either as it told me that getChargeRate was not defined.
Using Visual Studio Community, have NPM: Underscore and Tedious (for sql) installed. Just running it as a console app for now to test.
var Connection = require('tedious').Connection;
var config = {
userName: 'user',
password: 'passs',
server: 'somewhere.database.windows.net',
options: {
encrypt: true,
database: 'db-Test',
useColumnNames: true
var connection = new Connection(config);
connection.on('connect', function (err) {
// If no error, then good to proceed.
console.log("Connected".green);
toll("******-b77c-40e0-8f26-d44e98bc7264", "be45c903-****-****-b6ba-4b2fefa3d6b0");
});
function toll(chipId, locId) {
var carId = '';
var userOwner = '';
var charge = '';
var userBalance = '';
getcarIdandOwner = new Request(`SELECT car_id, userOwner FROM Cars WHERE carChipId = '${chipId}'`, function (err) {
if (err) {
console.log(err);
}
});
getcarIdandOwner.on('row', function (columns) {
carId = columns.car_id.value;
userOwner = columns.userOwner.value;
console.log('carId: ', carId, ' userOwner: ', userOwner);
});
getcarIdandOwner.on('done', function (rowCount, more) {
console.log(rowCount + ' rows returned');
if (rowCount = 1) {
console.log('Car Rows Returned Ok'.green);
} else {
console.log('Fatal Error: More than 1 Car Row Returned'.red);
};
});
connection.execSqlBatch(getcarIdandOwner);
getChargeRate = new Request(`SELECT Charge FROM locations WHERE location_id = '${locId}'`, function (err) {
if (err) {
console.log(err);
}
});
getChargeRate.on('row', function (columns) {
charge = columns.charge.value;
console.log('Charging account: ', userOwner, '$', charge);
});
connection.execSqlBatch(getChargeRate);
}
There is some documentation at http://tediousjs.github.io/tedious/api-connection.html which states:
Only one request at a time may be executed on a connection. Once a
Request has been initiated (with callProcedure, execSql, or
execSqlBatch), another should not be initiated until the Request's
completion callback is called.
So your code should be someting like this:
function toll(chipId, locId) {
var carId = '';
var userOwner = '';
var charge = '';
var userBalance = '';
getcarIdandOwner = new Request(`SELECT car_id, userOwner FROM Cars WHERE carChipId = '${chipId}'`, function (err) {
if (err) {
console.log(err);
} else {
getChargeRate = new Request(`SELECT Charge FROM locations WHERE location_id = '${locId}'`, function (err) {
if (err) {
console.log(err);
}
});
getChargeRate.on('row', function (columns) {
charge = columns.charge.value;
console.log('Charging account: ', userOwner, '$', charge);
});
connection.execSql(getChargeRate);
}
});
getcarIdandOwner.on('row', function (columns) {
carId = columns.car_id.value;
userOwner = columns.userOwner.value;
console.log('carId: ', carId, ' userOwner: ', userOwner);
});
getcarIdandOwner.on('done', function (rowCount, more) {
console.log(rowCount + ' rows returned');
if (rowCount = 1) {
console.log('Car Rows Returned Ok'.green);
} else {
console.log('Fatal Error: More than 1 Car Row Returned'.red);
};
});
connection.execSqlBatch(getcarIdandOwner);
}