Is there any way to get data from the database without using async/await in Nest.js? - node.js

Is there any way to use callback function for getting the data from the database using typeorm in nest.js and process that data, after that I want to send a response.

I am not sure that I understood your question correctly, but out of the box, you can use TypeORM (assuming you use a SQL DB, Mongoose works similarly, though). The repository functions return a Promise<>, so you could use something like this (from the docs):
return this.photoRepository
.find()
.then(result => {//... your callback code goes here...
});
You could wrap this code in a function getModifiedResult(cb){} and pass the callback into it. Secondly, Remember that async/await is just syntactic sugar for promises, so the above is equivalent to:
result = await this.photoRepository.find();
cbAction = //... do something with your result here
return cbAction;
Again, you could just wrap this.
Another idea is to wrap the promise in an Observable, using the RxJS from operator (fromPromise for RxJS versions < 6). You can then put your callback into the subscription:
//... Note that this returns a subscription for you to unsubscribe.
return from(this.photoRepository
.find()
.then(result => result))
.subscribe(result => //... your callback code
);
If you go down that route, however, it may be worthwhile to modify your results using RxJS operators, like map, switchMap,....

You can just use the from/of operators from rxjs.
Example
create(user: UserInterface): Observable<UserInterface> {
return from(this.userRepository.save(newUser))
}
And if you want you can also pipe the outcome
create(user: UserInterface): Observable<UserInterface> {
return from(this.userRepository.save(user)).pipe(
map((user: UserInterface) => user))
)
}

The answer is that you can use observables and / or promises (async await). I often use an observable for the wrapper function and then promises for addition work in a pipe. I'm not sure why I don't use observables for everything but it doesn't matter.
TypeORM integrates nicely with Nestjs and the docs show how to do the basics. With Postgres there is a problem with arrays that I'm trying to figure out though. An SO post and a Github issue have gone unanswered.

It looks like TypeORM, along with most modern JS packages, have been built with only promises in mind. Callbacks are, for the most part, not used in many programs today unless absolutely necessary, as promises and async/await syntax make the code much cleaner and more readable than the possible callback hell you may enter when using callbacks. It does look like sequelize accepts callbacks, and there are some docs in the recipes section about how to use NestJS with Sequelize

This is not much to do with Nest itself, it's just how you write your code and handle whatever libraries you might have. Let's say you have your database fetching function with a callback:
function findUsersWithCallback(function callback() {
// do something with db
callback(err, results);
});
You can wrap this into a promise-like function with, say, util.promisify
const findUsersPromisified = require('util').promisify(findUsersWithCallback);
What's left is to use your standard Nest provider:
#Injectable() UsersService {
findUsers() {
return findUsersPromisified();
}
}
Now your UsersService behaves like the rest of the framework, and your old callback-based code is nicely wrapped so you can safely ignore it.

Related

Calling a function that returns a AsyncIterableIterator without using "for await" block

I'm writing an AWS Lambda function in TypeScript using the Node.js runtime. I'm using a "batchDelete" function from a DynamoDB ORM library which returns an AsyncIterableIterator type.
According to the documentation here https://github.com/awslabs/dynamodb-data-mapper-js#batchDelete, I should invoke the method with a for await loop like this:
for await (const found of mapper.batchDelete(toRemove)) {
// items will be yielded as they are successfully removed
}
This all works great but the problem comes in where if I enable ESLint on my project. The default rules throw an error because the for await block is empty. I also get a warning because the found constant is never used. I have no use for the found constant and don't want to log it. I was wondering if there was another way to call an AsyncIterableIterator function where we disregard what is returned and don't have the empty block?
If you don't care about the results of the iteration, then you should probably just do something like this:
await Promise.all(toRemove.map(item => mapper.delete(item));
To use the mapper.batchDelete(toRemove) result more directly, you have to allow for multiple levels of promises. Perhaps you could do this:
await Promise.all(await mapper.batchDelete(toRemove)[Symbol.asyncIterator]());
In doing this, await mapper.batchDelete(toRemove)[Symbol.asyncIterator](), that would get you the default async Iterator and then passing it to Promise.all() would iterate it to get an iterable of promises. Unfortunately, in building it to make this easier:
for await (const found of mapper.batchDelete(toRemove))
they made it a bit more difficult to just get an array of promises out of it.
FYI, here's a link to the code for the .batchDelete() method if you want to look at how it's implemented.

Adding a value from Mongoose DB into a variable in Node.js

I am still quite new to Node.js and can't seem to find anything to help me around this.
I am having an issue of getting the query from my last record and adding it to my variable.
If I do it like below: -
let lastRecord = Application.find().sort({$natural:-1}).limit(1).then((result) => { result });
Then I get the value of the variable showing in console.log as : -
Promise { <pending> }
What would I need to do to output this correctly to my full data?
Here is it fixed:
Application.findOne().sort({$natural:-1}).exec().then((lastRecord) => {
console.log(lastRecord); // "lastRecord" is the result. You must use it here.
}, (err) => {
console.log(err); // This only runs if there was an error. "err" contains the data about the error.
});
Several things:
You are only getting one record, not many records, so you just use findOne instead of find. As a result you also don't need limit(1) anymore.
You need to call .exec() to actually run the query.
The result is returned to you inside the callback function, it must be used here.
exec() returns a Promise. A promise in JavaScript is basically just a container that holds a task that will be completed at some point in the future. It has the method then, which allows you to bind functions for it to call when it is complete.
Any time you go out to another server to get some data using JavaScript, the code does not stop and wait for the data. It actually continues executing onward without waiting. This is called "asynchronisity". Then it comes back to run the functions given by then when the data comes back.
Asynchronous is simply a word used to describe a function that will BEGIN executing when you call it, but the code will continue running onward without waiting for it to complete. This is why we need to provide some kind of function for it to come back and execute later when the data is back. This is called a "callback function".
This is a lot to explain from here, but please go do some research on JavaScript Promises and asynchronisity and this will make a lot more sense.
Edit:
If this is inside a function you can do this:
async function someFunc() {
let lastRecord = await Application.findOne().sort({$natural:-1}).exec();
}
Note the word async before the function. This must me there in order for await to work. However this method is a bit tricky to understand if you don't understand promises already. I'd recommend you start with my first suggestion and work your way up to the async/await syntax once you fully understand promises.
Instead of using .then(), you'll want to await the record. For example:
let lastRecord = await Application.find().sort({$natural:-1}).limit(1);
You can learn more about awaiting promises in the MDN entry for await, but the basics are that to use a response from a promise, you either use await or you put your logic into the .then statement.

Using async await with redis and bluebird in Nodejs

Correct me if I'm wrong here. This is what I do
client = Promise.promisifyAll(redis.createClient())
let reply = await client.getAsync('foo_rand000000000000')
console.log('reply',reply.toString())
And I got Unexpected token error.
I have this in my .babelrc
{
"presets": [
"es2015",
"stage-3"
]
}
Can someone point what I did wrong here.
As #Bergi points out, you need to wrap that in a async function
client = Promise.promisifyAll(redis.createClient())
async function main() {
let reply = await client.getAsync('whatever');
console.log('reply', reply.toString());
}
main();
To expand a bit, if you look at this docs http://babeljs.io/docs/plugins/transform-async-to-generator/ you'll notice that what they are doing is converting the function to a generator and yielding the resolved value of the promise to variable reply. Without wrapping this in a function that can be converted to a generator, you won't have the ability to pause execution and, therefore, would not be able to accomplish this.
Also, it should be noted, that this is not part of the standard. It is probably not going away, but the API could change. So I would not use this unless this is a toy project. You can accomplish something very similar using co or Bluebird.coroutine. They aren't quite as aesthetically pleasing, but the API won't change and the refactor once async/await get standardized will be trivial
Edit: add further explanation

To async, or not to async in node.js?

I'm still learning the node.js ropes and am just trying to get my head around what I should be deferring, and what I should just be executing.
I know there are other questions relating to this subject generally, but I'm afraid without a more relatable example I'm struggling to 'get it'.
My general understanding is that if the code being executed is non-trivial, then it's probably a good idea to async it, as to avoid it holding up someone else's session. There's clearly more to it than that, and callbacks get mentioned a lot, and I'm not 100% on why you wouldn't just synch everything. I've got some ways to go.
So here's some basic code I've put together in an express.js app:
app.get('/directory', function(req, res) {
process.nextTick(function() {
Item.
find().
sort( 'date-modified' ).
exec( function ( err, items ){
if ( err ) {
return next( err );
}
res.render('directory.ejs', {
items : items
});
});
});
});
Am I right to be using process.nextTick() here? My reasoning is that as it's a database call then some actual work is having to be done, and it's the kind of thing that could slow down active sessions. Or is that wrong?
Secondly, I have a feeling that if I'm deferring the database query then it should be in a callback, and I should have the actual page rendering happening synchronously, on condition of receiving the callback response. I'm only assuming this because it seems like a more common format from some of the examples I've seen - if it's a correct assumption can anyone explain why that's the case?
Thanks!
You are using it wrong in this case, because .exec() is already asynchronous (You can tell by the fact that is accepts a callback as a parameter).
To be fair, most of what needs to be asynchronous in nodejs already is.
As for page rendering, if you require the results from the database to render the page, and those arrive asynchronously, you can't really render the page synchronously.
Generally speaking it's best practice to make everything you can asynchronous rather than relying on synchronous functions ... in most cases that would be something like readFile vs. readFileSync. In your example, you're not doing anything synchronously with i/o. The only synchronous code you have is the logic of your program (which requires CPU and thus has to be synchronous in node) but these are tiny little things by comparison.
I'm not sure what Item is, but if I had to guess what .find().sort() does is build a query string internally to the system. It does not actually run the query (talk to the DB) until .exec is called. .exec takes a callback, so it will communicate with the DB asynchronously. When that communication is done, the callback is called.
Using process.nextTick does nothing in this case. That would just delay the calling of its code until the next event loop which there is no need to do. It has no effect on synchronicity or not.
I don't really understand your second question, but if the rendering of the page depends on the result of the query, you have to defer rendering of the page until the query completes -- you are doing this by rendering in the callback. The rendering itself res.render may not be entirely synchronous either. It depends on the internal mechanism of the library that defines the render function.
In your example, next is not defined. Instead your code should probably look like:
app.get('/directory', function(req, res) {
Item.
find().
sort( 'date-modified' ).
exec(function (err, items) {
if (err) {
console.error(err);
res.status(500).end("Database error");
}
else {
res.render('directory.ejs', {
items : items
});
}
});
});
});

Node.js // A module to manage a sqlite database

I managed to create a module to handle all the database call. It uses this lib: https://github.com/developmentseed/node-sqlite3
My issues are the following.
Everytime I make a call, I need to make sure the database exist, and if not to create it.
Plus, as all the calls are asynchronous, I end up having loads of functions in functions in callbacks ... etc.
It pretty much looks like this:
getUsers : function (callback){
var _aUsers = [];
var that = this;
this._setupDb(function(){
var db = that.db;
db.all("SELECT * FROM t_client", function(err, rows) {
rows.forEach(function (row) {
_aUsers.push({"cli_id":row.id,"cli_name":row.cli_name,"cli_path":row.cli_path});
});
callback(_aUsers);
});
});
},
So, is there any way I can export my module only when the database is ready and fully created if it does not exist yet?
Does anyone see a way around the "asynchronous" issue?
You could also try using promises or fibers ...
I don't think so. If you make it synchronous, you are taking away the advantage. Javascript functions are meant to be that way. Such a situation is referred to as callback hell. If you are facing problems managing callbacks then you can use these libraries :
underscore
async
See these guides to understand basics of asynchronous programming
Node.js: Style and structure
Using underscore.js managing-callback-spaghetti-in-nodejs
Using async.js node-js-async-programming

Resources