Return data from imported module which is Asynchronous - javascript

I have read many articles relating my issue such as (Returning a variable from a function in an imported module and NodeJS can't returned data from imported module is undefined) I also read (Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference and How do I return the response from an asynchronous call?) but im still stuck, I tried all the solutions by my issue is still persistent.
I am new to JS and am new to promises and await, which is mainly why I am confused.
I am using a simple mongoose function,
//Find and return user object function
async function findUser(associatedUser) {
try {
//Find a user based on given info
const foundUser = await User.find({ associatedUser: associatedUser });
//It returns a list of object, but usually its just one object. So we just get that one object
const foundUserObject = foundUser.find(o => o.associatedUser == associatedUser);
return foundUserObject;
} catch (err) {
console.log(err);
process.exit(1);
}
}
The function finds a user based on their name and returns it, in the local file I can access the function return value like this
foundUserObject = await findUser(associatedUser);
and it works.
However when I import the module, and give an input
const MongoDBModule = require('./index');
MongoDBModule.findUser(associatedUserPrompt)
It always returns undefined, when I try to make my return a promise in the original code
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(FoundUserObject);
}, 5000);
});
which is what some links told me to do I still get undefined; I think its because im returning a static value and not a request but im not too sure
When I try to put the return in an async function I get this error 'await' has no effect on the type of this expression
and when I try to use
MongoDBModule.findUser(associatedUserPrompt).then(value => {
console.log(value);
});
I get
TypeError: Cannot read properties of undefined (reading 'then')
at Object.<anonymous> (D:\Programming Related\MongooseTests\testingimport.js:18:45)
at Module._compile (node:internal/modules/cjs/loader:1226:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1280:10)
at Module.load (node:internal/modules/cjs/loader:1089:32)
at Module._load (node:internal/modules/cjs/loader:930:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:23:47
Node.js v18.14.0
From what I read this has something to do with a synchronous function trying to access an asynchronous return function, and I read many posts and tried everything but I'm really stuck. I just need to know how to not return undefined and return the object which I'm supposed to be getting.
This is what I'm supposed to get --
{
associatedUser: '971567800902#c.us',
currentContext: 'none',
name: 'none',
email: 'none',
subject: 'none',
budget: 'none',
phone: 'none',
message: 'none',
mailinglist: false,
_id: new ObjectId("63efda10621fb2247732d115"),
__v: 0
}
How I export the function
module.exports = {
findUserAndUpdateValues: function (associatedUser, givenObjectValue, newValue) {
findUserAndUpdateValues(associatedUser, givenObjectValue, newValue);
},
createUser: function (associatedUser, currentContext, name, email, subject, budget, phone, message, mailinglist) {
createUser(associatedUser, currentContext, name, email, subject, budget, phone, message, mailinglist);
},
findUser: function (associatedUser) {
findUser(associatedUser);
},
};

Either add the missing return
module.exports = {
// ...
findUser: function (associatedUser) {
return findUser(associatedUser);
},
};
Or don't create a wrapper function at all
module.exports = {
// ...
findUser
};

Related

Update data without manually property setter in DataStore using AWS Amplify with angular

I used aws-amplify for a very short time for my project. Recently, I'm facing a serious issue about data updating in DataStore in aws-amplify. After reading the docs from their official site I findout that, If I want to update data in DataStore it worked in Immutable way like this,
For creating data,
await DataStore.save(
new Post({
title: "My First Post",
rating: 10,
status: PostStatus.DRAFT
})
);
and for updating data ,
const original = await DataStore.query(Post, "123");
await DataStore.save(
Post.copyOf(original, updated => {
updated.title = `Any Title`;
})
);
there is no issue with creation but when I goes with update this line is a pain if you have more than 20 property in your object model. Because you have to write all those property and update with it .
updated.title = `Any Title`;
So, I want to update like this without writing all the property in manually,
const updatedTestResult = { ...this.testResult, ...this.testResultForm.value };
var result = await DataStore.save(TestResult.copyOf(this.testResult, updatedTestResult))
now it showing me this error,
TypeError: fn is not a function
at datastore.js:376:17
at produce (immer.esm.js:1:16034)
at Model.copyOf (datastore.js:375:32)
at test-result-form.component.ts:130:41
at Generator.next (<anonymous>)
at asyncGeneratorStep (asyncToGenerator.js:3:1)
at _next (asyncToGenerator.js:25:1)
at asyncToGenerator.js:32:1
at new ZoneAwarePromise (zone.js:1427:29)
at asyncToGenerator.js:21:1
or maybe there have another solution. Can you please me on that ?
TIA
I believe, copyOf function takes 2 parameters, 1st one is object and 2nd is callback. so, u can do something like this
await DataStore.save(
Post.copyOf(original, updated => {
...updated, ...this.testResultForm.value
})
);
Originally this question is answered in Github discussion. For updating a single property at a time, you could do the following:
async function updateTestResult(key, value) {
try {
const testResult = await DataStore.save(
TestResult.copyOf(originalTestResult, (updated) => {
updated[key] = value;
})
);
console.log("TestResult updated:", testResult);
} catch (error) {
console.error("Save failed:", error);
}
}
To update multiple properties at once, you could do the following:
async function updateTestResult(testResultForm) {
try {
const testResult = await DataStore.save(
TestResult.copyOf(originalTestResult, (updated) => {
for (const property in testResultForm) {
updated[property] = testResultForm[property];
}
})
);
console.log("TestResult updated:", testResult);
} catch (error) {
console.error("Save failed:", error);
}
}
if you want to see the original ansewer check out this link : https://github.com/aws-amplify/amplify-js/discussions/9984#discussioncomment-2959980

Example script provided by neo4j for JavaScript won't run

I am very new to the graph database ecosystem and for start I am experimenting with the neo4j. I would very much like to work with node and neo4j. So after a quick search I found neo4j-driver that is an officially supported driver for JavaScript and an example provided which is:
const neo4j = require('neo4j-driver')
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password))
const session = driver.session()
const personName = 'Alice'
try {
const result = await session.run(
'CREATE (a:Person {name: $name}) RETURN a',
{ name: personName }
)
const singleRecord = result.records[0]
const node = singleRecord.get(0)
console.log(node.properties.name)
} finally {
await session.close()
}
// on application exit:
await driver.close()
now when I run this code, I immediately get the following error:
SyntaxError: await is only valid in async function
Now I thought I understood the error that I would have to wrap the try-catch block with anonymous async function to get rid of the error. The changed code body is:
const config = {
"neo4j": {
"url": "neo4j://localhost",
"authUser": "neo4j",
"authKey": "adminPassword"
}
}
const neo4j = require("neo4j-driver");
const driver = neo4j.driver(
config.neo4j.url,
neo4j.auth.basic(config.neo4j.authUser, config.neo4j.authKey)
);
const session = driver.session();
(async () => {
try {
const result = await session.run('CREATE (a:Person {name: $name}) RETURN a', { name: 'Alice' });
const singleRecord = result.records[0];
const node = singleRecord.get(0);
console.log(node.properties.name);
} catch (error) {
console.log("Error Body: ", error);
} finally {
await session.close();
}
})();
await driver.close();
But to my dismay, I have run into another error that is very cryptic:
{ Neo4jError: Could not perform discovery. No routing servers available. Known routing table: RoutingTable[database=Sample database, expirationTime=0, currentTime=1592397056399, routers=[], readers=[], writers=[]]
at captureStacktrace (/Users/pc/node_modules/neo4j-driver/lib/result.js:263:15)
at new Result (/Users/pc/node_modules/neo4j-driver/lib/result.js:68:19)
at Session._run (/Users/pc/node_modules/neo4j-driver/lib/session.js:174:14)
at Session.run (/Users/pc/node_modules/neo4j-driver/lib/session.js:135:19)
at /Users/pc/neoNode.js:20:38
at Object.<anonymous> (/Users/pc/neoNode.js:31:3)
at Module._compile (module.js:653:30)
at Object.Module._extensions..js (module.js:664:10)
at Module.load (module.js:566:32)
at tryModuleLoad (module.js:506:12) code: 'ServiceUnavailable', name: 'Neo4jError' }
I also had some problems with this.
First off, Natam Oliveira is correct. You need to use the bolt protocol, and await promises needs to be within an async function. For some reason the neo4j protocol is used in some examples in the docs. Additionally it would seem both examples currently provided by Neo4j—in the driver-manual and javascript-driver section—causes errors if you use them outside of some kind of unspecified environment.
There were some clues on the npmjs pagckage page, though, so by working them into the existing code, I was at least able to spit out some data. However I'm also wondering on how you could make this work inside the async function, so an explanation to how that could work with this driver would be very welcome.
Here's what worked for me:
const neo4j = require('neo4j-driver')
const cnx = {
user: 'neo4j',
password: 'some passphrase',
uri: 'bolt://localhost:7687'
}
const driver = neo4j.driver(cnx.uri, neo4j.auth.basic(cnx.user, cnx.password))
driver.verifyConnectivity()
.then((cnxMsg) => {
console.log(cnxMsg)
})
const session = driver.session({ database: 'neo4j' })
session.run('MATCH (n:Movie) RETURN n LIMIT 5')
.subscribe({
onKeys: keys => {
console.log(keys)
},
onNext: record => {
console.log(record.get('n').properties.title)
},
onCompleted: () => {
session.close()
},
onError: error => {
console.error(error)
}
})
This spits out some movies using the streaming API as seen in the NPM documentation. (Note: It will only work if you started/installed the Movie database, so double check that you didn't delete it, as its deletion is also part of the Neo4j tutorial.) Now just change the MATCH Cypher query to whatever you like, and play around with the output, for instance by piping it to Express.
Sources:
https://neo4j.com/docs/driver-manual/current/client-applications/
https://neo4j.com/developer/javascript/#javascript-driver
https://www.npmjs.com/package/neo4j-driver
https://neo4j.com/docs/api/javascript-driver/current/
first of all, I think your URL should be "url": "bolt://localhost:7687"
And you still with await driver.close() outside an async function
If you are starting to use neo4j, look for an OGM (Object Graph Model) to help you.

Node JS : Route.get() requires a callback function but got a [object Undefined] While using ES6 Modules

Route File
scoreboardroute.js
import { scoreRouteController } from '../controllers/scoreboardcontroller';
const SCOREROUTE = app => {
app.route('/getAllScores').get(scoreRouteController.getAllScores);
};
export { SCOREROUTE };
Controller File
scoreboardcontroller.js
import { scoreBoardModel } from '../model/scoreboardmodel';
class scoreRouteController {
getAllScores = (req, res) => {
scoreBoardModel.getAllScoresList((err, response) => {
if (err) {
res.send(err);
}
res.send(response);
});
};
}
export { scoreRouteController };
Model File:
scoreboardmodel.js
import { db } from './db';
class scoreBoardModel {
getAllScoresList = callback => {
db.query('Select * from users', (err,response) => {
callback(err, response);
});
}
};
export { scoreBoardModel };
I was trying to use ES6 features like class and arrow functions inside my application. While I'm trying to execute this code it hit the following error. I don't know what went wrong. And I'm really new for node JS server.
So, Can anyone please help me to get rid of this error.
Error:
node_modules/express/lib/router/route.js:202
throw new Error(msg);
^
Error: Route.get() requires a callback function but got a [object Undefined]
at Route.(anonymous function) [as get] (/node_modules/express/lib/router/route.js:202:15)
at SCOREROUTE (/app/routes/scoreboardroute.js:4:32)
at Object. (/server.js:26:1)
at Module._compile (internal/modules/cjs/loader.js:689:30)
I'm finding the answer.
While importing the class I'm using like Object import. So, changed it like
import scoreRouteController from '../controllers/scoreboardcontroller';
And I'm not going to use so many instances for my application. So, I assign static keyword for my every function inside my class.
static getAllScores = (req, res) => {.....
While exporting I was not exporting an Obj. I changed into default class export.
export default scoreRouteController;
And finally, it works.

Module exports async function undefined can't await

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?

"Cannot find global value 'Promise'" Error in Mocha test

The following has to do with a full stack Node.js problem. It involves Express, Mongoose, and Mocha.
I have a controller module with a function that processes an HTTP call. It basically takes Request and Response objects as its arguments. Within it, it pulls Form data out of the Request object and stores data in multiple MongoDB instances. In order to accomplish multiple data stores we use a call to Promise.all. This is done in an async function. Something like the following
async function saveData(data1 : Data1Interface, data2 : Data2Interface,
res: Response)
{
try
{
//Call 3 save methods each returning promised. Wait fLoginInfoModelor them all to be resolved.
let [data1Handle, data2Handle] = await Promise.all([saveData1(data1),
saveData2(data2)]);
//if we get here all of the promises resolved.
//This data2Handle should be equal to the JSON {"id" : <UUID>}
res.json(data2Handle);
res.status(200);
}
catch(err)
{
console.log("Error saving registration data” + err);
res.json( {
"message" : "Error saving registration data " + err
});
res.status(500);
}
}
Within saveData1 and saveData2 I am doing something like:
function saveData1(data : DataInterface) : Promise<any>
{
let promise = new Promise(function(resolve : bluebird.resolve, reject : bluebird.reject)
{
Data1Model.create(data, function(err,
data){
….
.
.
This works fine! We are doing all of this in Typescript.
However I want to test this method using Mocha. This is where the problems start. For the sake of brevity I am only using one of the Mongoose Models in this example. If I try to run the following code as a mocha unit test I get the following error message. I am not sure what it wants as far as a Promise constructor?
TSError: ⨯ Unable to compile TypeScript
Cannot find global value 'Promise'. (2468)
server/controllers/registration.server.controller.ts (128,17): An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your --lib option. (2705)
server/controllers/registration.server.controller.ts (134,66): 'Promise' only refers to a type, but is being used as a value here. (2693)
Note that line 128 is the line that starts “async function saveData(data1 : Data1Interface, data2 : Data2Interface, res: Response)
“
The following two lines
“let [data1Handle, data2Handle] = await Promise.all([saveData1(data1),
saveData2(data2)]); “
and
“ let promise = new Promise(function(resolve : bluebird.resolve, reject : bluebird.reject)”
produce the “'Promise' only refers to a type, but is being used as a value here.” errors.
The Mocha unit test code looks something like the following.
import 'mocha';
import { expect } from 'chai';
import * as sinon from 'sinon';
var config = require('../config/config');
import * as sinonmongoose from 'sinon-mongoose';
import * as controller from './registration.server.controller';
import { Request, Response } from 'express';
import { Data1Interface, Data1Model} from '../models/data1.server.model';
import * as mathUtilities from '../utilities/math.utilities';
import mongoose = require("mongoose");
import * as bluebird from 'mongoose';
(mongoose as any).Promise = bluebird.Promise;
//NOTE: This currently does not work.
describe('Registration related tests', function () {
beforeEach(()=>{
});
afterEach(()=>{
//sinon.restore(authentication);
});
it('should return 200 OK valid outline', function (done) {
let dummyRequest: any = {
body: {
username: "awhelan",
password: "awhelan",
firstName : "Andrew",
lastName: "Whelan",
email: "awhelan#srcinc.com",
source: "none",
school: "Arizona",
consent: true,
dob: "1970-03-10",
gender:"Male",
interviewconsent: true,
recordingconsent: true
}
};
let id = mathUtilities.createId("Andrew", "Whelan", "awhelan#srcinc.com");
let retJson = "{id:" + id +"}";
let dummyResponse: any = {
json: function (data) {
expect(data).to.equal(retJson);
done();
return this;
},
sendStatus: function (code) {
expect(code).to.equal(200);
done();
return this;
}
};
let req: Request = dummyRequest as Request;
let res: Response = dummyResponse as Response;
let mock = sinon.mock(Data1Model).expects('create').yields(null, { nModified: 1 });
controller.register(req, res);
sinon.restore(Data1Model.create);
});
});
Note that the suggestion in ts An async function or method in ES5/ES3 requires the 'Promise' constructor” doesn’t help.
Any suggestions as to how I might move past these errors would be appreciated.
-Andrew
Fixed it by installing es6-shim typings.

Categories

Resources