I was trying to fetch data from neo4j database.
Here is my function for getting data from database which I found on their official website and have modified it little bit:
function receiveDataFromDB() {
var neo4j = require("neo4j-driver");
var driver = neo4j.driver(
"neo4j://localhost",
neo4j.auth.basic("neo4j", "something")
);
console.log(driver);
var session = driver.session({
database: "neo4j",
defaultAccessMode: neo4j.session.READ,
});
session.run(`match (n) return n`).subscribe({
onKeys: (keys) => {
console.log(keys);
},
onNext: (record) => {
console.log(record.get("n"));
},
onCompleted: () => {
session.close(); // returns a Promise
},
onError: (error) => {
console.log(error);
},
});
}
So this function only console.log-s it:
but I want it to use outside the function. I've tried returning return record.get("n") inside onNext but got errors instead.
You can simply use the try-catch equivalent of your query, like this:
try {
const result = session.run(`match (n) return n`);
} catch (error) {}
finally {
session.close();
}
Or try setting your result in a variable, like this:
const result = [];
session.run(`match (n) return n`).subscribe({
onKeys: (keys) => {
console.log(keys);
},
onNext: (record) => {
result.push(record.get("n"));
},
onCompleted: () => {
session.close(); // returns a Promise
},
onError: (error) => {
console.log(error);
},
});
Related
I have the following API, the API is inserting into a table based on user selection from the client. User can select different material belonging to same experiment. In my payload, I have materials as array, experiment as string. I tried several ways to resolve my error. Following was the last try:
app.post("/insertMaterials", (req, res) => {
for (let mat of req.body["material"]) {
try {
oracledb.getConnection(
{
user: "some_user",
password: "some_pw",
connectString: "someConnStr",
},
function (err, connection) {
if (err) {
console.error("1" + err);
return;
}
connection.execute(
"INSERT INTO MATERIALS (ID, MAT_NAME, EXPR) VALUES((SELECT max(ID) + 1 FROM MATERIALS), :1, :2)",
[mat, req.body["experiment"]],
(err, result) => {
if (err) {
console.error("log " + err);
}
connection.commit();
connection.close();
}
);
}
);
} catch (error) {
console.log(error);
}
}
return res.status(200).json({
title: "SUCCESS: Materials Inserted",
});
});
I always get:
triggerUncaughtException(err, true / fromPromise /);
^
[Error: DPI-1002: invalid dpiConn handle] { errorNum: 0, offset: 0 }
Before I had a separate function of the block inside the for loop and I also tried with execeuteMany. Still same error. After trying lot other ways and reading in internet, I couldn't solve the issue. Except for finally catching uncaughtException and logging the error:
process.on('uncaughtException', (error, next) => {
let date = new Date()
errorLogStream.write(`Date: ${date}. Err: ${error.stack} \n`)
return
})
By catching this exception, my program does not break anymore and data is always inserted. But it would be great to know how and when this is raised and how this can be resolved or where if I am doing a mistake.
UPDATE
Payload example: {'material': ['F99999.7', 'J84845.4'], 'experiment': 'NA32R'}
Function:
async function addMatToExpr(exp, mat) {
let connection;
try {
connection = await oracledb.getConnection(
{
user: "some_user",
password: "some_pw",
connectString: "someConnStr",
});
result = await connection.execute("INSERT INTO MATERIALS (ID,
MAT_NAME, EXPR) VALUES((SELECT max(ID) + 1 FROM MATERIALS), :1, :2)",
[exp, mat], { autoCommit: true })
} catch (error) {
return res.status(404).json({
title: error,
});
} finally {
if (connection) {
try {
await connection.close()
} catch(error) {
console.log(error)
}
}
}
}
API:
app.post("/insertMaterials", (req, res) => {
for (let mat of req.body["materials"]) {
addMatToExpr(req.body["experiment"], mat)
}
});
Added the async/await function and the api that calls the function.
You need to 'await' the Oracle function calls so each completes before continuing. Currently the connection is being closed before the statement is executed.
See all the node-oracledb documentation and examples.
E.g.
async function run() {
let connection;
try {
connection = await oracledb.getConnection(dbConfig);
result = await connection.execute(sql, binds, options);
console.dir(result, { depth: null });
} catch (err) {
console.error(err);
} finally {
if (connection) {
try {
await connection.close();
} catch (err) {
console.error(err);
}
}
}
}
Noob in nodejs here and still trying to learn how nodejs works. Could you please let me know how can I pass the callback response from "getDatafromCosmosDB" function into a variable in the main function and print those values.
When I try to assign getDatafromCosmosDB to a variable "respdata" and try to print it, it is not working.
async function main(params, callback) {
const logger = Core.Logger('main2', { level: params.LOG_LEVEL || 'info' })
try {
logger.info('main action')
const respdata = getDatafromCosmosDB(function(response){
console.debug(response)
return response
});
console.debug(respdata)
} catch (e) {
console.debug(e)
}
}
exports.main = main
async function getDatafromCosmosDB(callback){
var query = new azure.TableQuery()
.top(5)
tableService.queryEntities('myCosmosTable', query, null, function (error, result, response) {
if (!error) {
console.log('success')
return callback(result.entries)
}
});
}
Try something like this,
import {
createTableService,
services,
ServiceResponse,
TableQuery
} from 'azure-storage';
getDatafromCosmosDB(): Promise<ServiceResponse> {
return new Promise(async (resolve, reject) => {
this.tableService.queryEntities(
this.tableName,
query,
null,
(error, _, response) => {
if (!error) {
resolve(response);
} else {
reject(error);
}
}
);
});
}
and invoke like,
this.getDatafromCosmosDB().then(data => {
console.log(data);
}
I apologize in advance because I have seen other questions on this very topic, but I do not understand what I am doing wrong and how to fix it. Please have a look at my code:
function getSum(productID) {
Rating.aggregate(
[
{
$group: {
_id: "$productID",
total: {
$sum: "$rating"
}
}
}
],
function (err, result) {
if (err) {
res.send(err);
} else {
//console.log("product-sum: " + req.body.productID)
const count = result.find(item => item._id === productID.productID);
console.log("getSum count: ", count.total);
return count.total;
}
}
);
}
router.route('/compute-rating').post((req, res) => {
console.log("compute Rating: ", req.body.data);
var productID = req.body.data;
var sum = getSum(productID).then( //getting the error here
res.json({ sum })
);
});
getSum() returns a valid number from count.total.
Once I get the sum, I plan to chain another .then onto the existing then and call another function with the productID, but I need to use the sum later in the computer-rating route.
In the code, I have a comment that shows where the error, "Cannot Read Property 'then' of Undefined", is occurring. Why am I getting this error and how can I fix it?
Thanks.
Edit:
I wanted to show my final solution so others could benefit from my experience. Hopefully I did not create any major Javascript violations in my code. I ended up using Promise.all because I had to perform a calculation based on 2 returned values.
function getSum(productID) {
return new Promise(async (resolve, reject) => {
const result = await Rating.aggregate( //sum of a column in MongoDB
[
{
$group: {
_id: "$productID",
total: {
$sum: "$rating"
}
}
}
]
);
try {
var sum = result.find(item => item._id === productID.productID);
if (sum !== undefined) {
resolve(sum);
console.log("getSum sum: ", sum);
}
else {
reject("invalid product id");
}
}
catch (e) {
reject(e);
}
});
}
function getCount(productID) {
return new Promise(async (resolve, reject) => {
var result = await Rating.countDocuments(productID)
.then(count => {
console.log("getCount count:", result);
var documentCount = { count: count }
resolve(documentCount);
})
.catch(err => reject(err));
});
}
router.route('/compute-rating').post((req, res) => {
console.log("compute Rating: ", req.body.data);
var productID = req.body.data;
Promise.all([getSum(productID), getCount(productID)])
.then(results => {
console.log("compute rating results: ", results);
if (results[1].count > 0) {
res.status(200).json({ rating: results[0].total / results[1].count });
}
else {
res.status(200).json({ rating: 0 });
}
})
.catch(err => {
res.status(400).json({ error: err });
})
});
Your getSum doesn't return anything. You are returning only from the callback function, not the getSum function.
You should make it async.
And also you are doing res.send in that function, while not having access to res object.
For example you can do it like this:
async function getSum(productID) {
const result = await Rating.aggregate(
[
{
$group: {
_id: "$productID",
total: {
$sum: "$rating"
}
}
}
]
);
const count = result.find(item => item._id === productID.productID);
console.log("getSum count: ", count.total);
return count.total;
}
router.route('/compute-rating').post((req, res) => {
console.log("compute Rating: ", req.body.data);
var productID = req.body.data;
// EDIT: This should work
getSum(productID).then(sum => {
res.json({ sum })
});
});
then only works on functions that return a promise. your function getSum is not returning anything, if Rating.aggregate function returns a promise, aka accepts a then, then you should return this aggregate, simply add return before calling it.
Now if aggregate doesn't return a promise, and I'm guessing so because you're passing a callback function to it, you might want to return a promise that resolves using promise.resolve in this callback body.
I want to refactor code for chain of promises by async, await. I have sequelize ORM for DB management and the code is written in AWS Lambda function having multiple middleware. In such cases I have to traverse code for multiple entries using sequelize transactions. It is easy to manage using promise.all() but need to change it to async await syntax for cleaner code.
Here are my demo code.
/* get all invoice where user_id === current logged in user, and where status != "paid" */
db.Invoice.findAll({
where: {
user_id: currentLoggedInUser,
status: {
$ne: "paid"
}
}
}).then(invoices => {
if (!invoices || invoices === null) {
return false;
}
function addScheduledTransactionAttempts(invoice, tryPayOnDate, t) {
return new Promise((resolve, reject) => {
/* check If any ScheduledTransactionAttempts exists for this invoice.id */
db.ScheduledTransactionAttempts.find({
where: {
invoice_id: invoice.id
}
})
.then(function(attempts) {
if (attempts) {
attempts
.destroy({}, {
transaction: t
})
.then(deletedAttempts => {
console.log("Attempts Record Deleted: ", deletedAttempts);
})
.catch(error => {
reject(error);
t.rollback();
});
}
return db.ScheduledTransactionAttempts.create({
invoice_id: invoice.id,
payment_source_id: PaymentMethodId,
try_pay_on_date: tryPayOnDate,
stripe_customer_id: currentLogInStripeCustomerId
}, {
transaction: t
})
.then(function(attempt) {
resolve(attempt.id);
})
.catch(error => {
reject(error);
t.rollback();
});
})
.catch(error => {
reject(error);
t.rollback();
});
});
}
//Run transaction to addScheduledTransactionAttempts
return db.sequelize.transaction().then(function(t) {
let promiseArr = [];
var i = 0;
invoices.forEach(function(invoice) {
var schedulePaymentDate = moment(paymentDate);
if (invoice) {
let tryPayOnDate = schedulePaymentDate
.add(i, "month")
.format("YYYY-MM-DD");
promiseArr.push(
addScheduledTransactionAttempts(invoice, tryPayOnDate, t) //calling above function
);
i++;
}
});
//now execute promise all
Promise.all(promiseArr)
.then(function(result) {
t.commit();
return true;
})
.catch(function(err) {
t.rollback();
return false;
});
});
});
In the above code I want to change
Promise.all(promiseArr)
which is calling
addScheduledTransactionAttempts
function to do DB queries to simple async function await process to make it easy simpler understandable without having multiple .then or .then inside then promises.
Any help regarding would be appreciated,
Thanks.
It's quite simple. await is valid when invoking methods that return a Promise. All of your SDK methods already return a promise, so refactoring should be quite straight forward. Here's something to get you off ground:
const processInvoices = async currentLoggedInUser {
const invoices = await db.Invoice.findAll({
where: {
user_id: currentLoggedInUser,
status: {
$ne: 'paid',
},
},
});
if (yourOwnLogicForInvoicesObject) {
for (const invoice of invoices) {
const potentiallyFoundInvoice = await db.ScheduledTransactionAttempts.find({
where: {
invoice_id: invoice.id,
},
});
if (potentiallyFoundInvoice) {
await addScheduledTransactionAttempts(potentiallyFoundInvoice)
}
}
}
}
const addScheduledTransactionAttempts = async invoice => {
console.log('Do something with your invoice', invoice)
}
Long story short: refactor the code inside your functions into smaller functions and make these new functions async, just like I did with addScheduledTransactionAttempts and processInvoices
More on async/await
I am having difficulties getting and moving a response from the following functions in a chain.
The values exist further up but however I try to pass them down, the output always ends up empty.
I'm new to async/await in nodejs, but assumed they didn't need to be resolved like or with a promise.
let output = {
keywords: [],
steps: [],
twitter: []
}
async function requestGoogle (output) {
const GoogleResponse = await (
new Promise((resolve, reject) => {
const loc = utilities.checkOrigin()
googleMaps.directions({
origin: loc.origin,
destination: loc.destination
}, (error, response) => {
if (error) resolve(error)
resolve({
response
})
})
})
)
return GoogleResponse
}
async function requestTwitter (output) {
try {
const loc = utilities.checkOrigin()
const twitterParams = {
count: details.twitter.count,
geocode: loc.lat + loc.long + details.radius,
lang: details.lang,
result_type: 'recent'
}
await output.keywords.map(keyword => {
TwitterClient.get('search/tweets', {q: 'query'}, (error, tweets, response) => {
if (error) console.log(error)
tweets.statuses.map(tweet => {
output['twitter'].push({
text: tweet.text
})
})
})
})
return output
} catch (error) {
console.error('++ requestTwitter flow', error)
}
}
flow.commuteCheck = () => {
return requestGoogle(output)
.then(requestTwitter(output))
.then(console.log(output))
}
The response is unmodified and empty:
{ keywords: [], steps: [], twitter: [] }
full file on Github
.then(requestTwitter(output)) calls requestTwitter(output) and passes its return value (a promise) into then. But then expects a callback, not a promise. Similarly with .then(console.log(output)).
You probably meant to wrap those in functions:
flow.commuteCheck = () => {
return requestGoogle(output)
.then(() => requestTwitter(output))
// ---^^^^^^
.then(() => console.log(output))
// ---^^^^^^
}
FWIW, if requestGoogle and requestTwitter don't have to run in series, you can overlap them so the requests run concurrently:
flow.commuteCheck = () => {
return Promise.all([
requestGoogle(output),
requestTwitter(output)
]).then(() => console.log(output));
}
It's also probably worth noting that in both cases, the promise resolves with no useful value for the caller. You might have it resolve with output. To provent crosstalk between requests, you could also make output not be a module global that gets reused, but instead an object you create for each request:
flow.commuteCheck = () => {
const output = output = {
keywords: [],
steps: [],
twitter: []
};
return Promise.all([
requestGoogle(output),
requestTwitter(output)
]).then(() => {
console.log(output);
return output;
});
}