is graphql executing mongoose queries automatically? - node.js

If i return a query from a graphql resolver like so:
someResolver = () => SomeModel.find()
it just works and responds with a database result.
How is this happening ? Why don't i have to call .exec() on it for example ?

Although Model.find() return a Query, but it's a PromiseLike type.
Here is the doc: http://mongoosejs.com/docs/promises.html#built-in-promises
And, in graphql resolver, you can return a promise or use async/await or just return a constant value
https://graphql.org/learn/execution/#asynchronous-resolvers
During execution, GraphQL will wait for Promises, Futures, and Tasks to complete before continuing and will do so with optimal concurrency.
Model.find().exec() return a fully-fledged promise, it works fine too.

Related

Does Model.populate() return a promise?

I am following a guide on Node.js and Mongoose. Developing some code for an eCommerce store. I have two code snippets, both use populate() on a Model however one code snippet requires execPopulate() to return a promise but the other doesn't. I have tried removing execPopulate and adding it to the other method but I get errors on both.
Any explanation is welcomed and appreciated. Thank you!
Populate() return «Query» this see here and according to mongoose docs again Query is not a promise.
Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. However, unlike promises, calling a query's .then() can execute the query multiple times.
So if you want to use populate as a promise use execPopulate()

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.

Is there any way to get data from the database without using async/await in Nest.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.

how to run foreach in synchronous way in nodejs

I am running email alert sending job in nodejs, due to asyncronous, hits are too many. Even elastic search throwing timeout exception.
Along with node i am using Q promise.
Please tell me how to fix this issue.
If you can use new Node, google how to use async/await, then you can for-cycle all requests and await them.
If you cant, you can do it recursively:
function processAllOneByOne(fns, i){
if (i >= fns.length) { return Promise.resolve({done:true}) }
fns[i]().then(() => processAll(fns, i+1));
}
And call it with
processAllOneByOne(fns, 0)
Please note that once you create promise you CANT handle how it is executed "inside". So you need to have fns which is array of function, calling that function creates and return Promise you want to wait to finish.
So push there something like fns.push(() => sendAlert(some, paramaters)), where sendAlert is creating the Promise you need.

Mongoose Model.count() does not run callback as documented

I am following almost the exact example for Model.count() from the Mongoose docs:
User.count({ type: 'jungle' }, function (err, count) {
console.log('I do not ever run');
});
This should print 'I do not ever run'. Instead, it returns a Query object - which should not happen, according to the docs, as I am providing a callback. How can I make the callback function run? Is there some circumstances where the callback is not run?
Using mongoose#3.6.17. Thanks!
Make sure you've connected to the database before calling any model functions. Mongoose will just queue up the count query until you connect otherwise.
See this question of the FAQ.

Resources