promise pending error in mongodb and nodejs - javascript

I have written node.js code for getting some number using mongodb database.this is my code for that
MongoClient.connect('mongodb://localhost:27017/mongomart', function(err, db) {
assert.equal(null, err);
var numItems=db.collection('item').find({"category":category}).count();
callback(numItems);
});
This mongodb query runs correct on mongo shell but it is giving error when using with node.js
Promise <Pending>
I don't know what is this "promise" ? Please help..

node.js code is asynchronous so that numItems won't contain count of items - it rather contains Promise that contains count of items when resolved. You defenetely have to master the basics of node.js and asynchronous programming. Try to modify your code like this
MongoClient.connect('mongodb://localhost:27017/mongomart', function(err, db) {
assert.equal(null, err);
db.collection('item').find({"category":category}).count()
.then(function(numItems) {
console.log(numItems); // Use this to debug
callback(numItems);
})
});
For native Promise check out documentation https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise
Also look at bluebird promises https://github.com/petkaantonov/bluebird

A promise is a substitute temporary value that is given while you wait on the real value. To get the real value do
numItems.then(function (value) { callback(value) });
Or better yet, return the promise from your function, and let they implement it using the Promises pattern, instead of the callback pattern.

Had the same problem. Don't know if it's still relevant to you, but this is what solved it for me:
var category = 'categoryToSearch';
var cursor = db.collection('item').find({'category':category});
cursor.count(function (err, num) {
if(err) {
return console.log(err);
}
return num;
});

I drove myself bananas trying to solve a similar problem, where the document.save() option just gave Promise{pending} no matter what I did. Here's what I did:
Change (req,res) to async(req,res).
Change var post = doc.save() to var post = await doc.save().
Finally, log in to MongoDB web, and change accessible IP addresses to 0.0.0.0 (all addresses). Not doing this can cause issues sometimes even when your IP is whitelisted.

try this:
MongoClient.connect('mongodb://localhost:27017/mongomart', async (err, db) => {
assert.equal(null, err);
var numItems= await db.collection('item').find({"category":category}).count();
callback(numItems);
});
(adding the await and turn this function to async function)

Related

Get inserted ID or changed rows in sqlite3

I recently started working with the sqlite3 package in Node.js. Primarily I'm using the run, all and get functions. Since I like async/await more and those functions are taking callbacks, I used promisify from the util package to make them use promises that I can await.
import sqlite from 'sqlite3'
import { promisify } from 'util'
const db = new sqlite.Database('./myDatabase.db', (err) => {
if (err) {
return console.error(err.message);
}
console.log('Connected to the database.');
});
db.run = promisify(db.run)
db.all = promisify(db.all)
db.get = promisify(db.get)
This works with async/await however a problem shows up when I try to insert or update data using run().
const changedRows = await db.run("UPDATE races SET is_open = false WHERE code = ?", [racecode])
When I want to fetch the inserted ID or the affected rows I get undefined. That makes sense because the run function usually has no argument for a result thus resolve yields undefined.
From the docs:
db.run(`INSERT INTO langs(name) VALUES(?)`, ['C'], function(err) {
if (err) {
return console.log(err.message);
}
// get the last insert id
console.log(`A row has been inserted with rowid ${this.lastID}`);
});
The question is: Can I even get this.lastID from a promisified run ? I know there are some wrapper packages for sqlite3 out there, but I wanna try to use as few packages as possible before adding new ones.

MongoDB / EJS: How to make synchronous query and render result values in EJS

I'm struggling a little bit with the concepts of asynchronous programming and I would appreciate some help/guidance from someone.
Basically, I'm developing a node.js web server that's connected to a mongodb database.
I'm using EJS to generate HTML files as you can see below.
app.get("/", function(req, res){
res.render('home', {date: getData.todaysDate(), n: getData.todaysIncidents(), nTot: getData.totalIncidents()});
});
Most of these values ('n' and 'nTot') are obtained by querying my database and then doing some other operations, as you can see in the following example code sample.
//------getData.js------//
exports.todaysIncidents = function() {
let server_n = 0;
Incident.find({dia: {$gt:y}}, function(err, result) {
if (err) {
console.log(err);
} else{
//do some stuff...
server_n = 12345
}
}
});
return server_n;
};
Here is the problem: The values printed in the HTML file are always those used for variable initialization, such as 0 for variable 'server_n'. After doing some research, I understand that this happens because .find(...) is an asynchronous function so the program executes right away the instruction "return server_n;", which means that on the HTML file the value showed will be 0 and not 12345.
I already looked at other questions here in StackOverflow, but I'm struggling to understand a possible fix to this issue, I mean I can't be the only one going through this, right?
Could you please provide some basic explanation of how I could go around this issue? I'm still learning and a lot of these concepts remain hard to understand.
Thank you very much.
Yes, you are right that the problem is as a result of improper handling of asynchronous operations like querying the DB. So how do you fix it?
Using async/await:
There are multiple options to handle asynchronous operations in NodeJS, however, I would strongly recommend using async/await, it's syntactically clean and easy to understand.
To put it simply, async/await is a way of specifying and dealing with asynchronous operations. You use the async keyword to specify that a function is asynchronous, and you use the await keyword to wait for an asynchronous operation. One key thing to note is that you can only use the await keyword inside an async function. You can read more about async/await here.
If your nodeJS version is 7.6 or higher, async/await is supported out of the box, however, if you are using a lower version and can't upgrade, you can set up build tools like Babel to be able to use javascript features supported in newer ECMAScript spec.
When using async/await, your code should be something like this.:
//------getData.js------//
// NOTE: the typeof todaysIncidents is not more the regular function,
// it's now an AsyncFunction because of the async keyword
exports.todaysIncidents = async function () {
let server_n = 0;
try {
// In simple terms, the await keyword here would ensure that the DB query
// resolves or reject before moving on to the next statement
const incident = await Incident.find({ dia: { $gt: y } });
// The incident variable stores the result of the query
server_n = 12345
} catch (err) {
// Handle error from the DB query
console.log(err);
}
return server_n;
};
.
//------The router------//
// NOTE: You also need to make the route handler an AsyncFunction
app.get("/", async function (req, res) {
// You can await the differeint DB queries in here to ensure they resolve(or reject) before rendering the view
const todaysDate = await getData.todaysDate();
const todaysIncidents = await getData.todaysIncidents();
const totalIncidents = await getData.totalIncidents();
res.render('home', { date: todaysDate, n: todaysIncidents, nTot: totalIncidents });
});

NodeJS - Sending SQL Results to Google Sheets

I am trying to write a script that will query a local database and send the results to a Google Spreadsheet. Where I am currently stuck and looking for help is how do I get the results of my query.
var myQuery = [];
function runQuery(query, callback) {
client.connect(function (err) {
if (err) throw err;
client.query(query, function (err, result) {
if (err) {
console.log(err);
}
callback({ result: result });
client.end(function (err) {
if (err) throw err;
});
});
});
}
runQuery('SELECT item_number FROM item WHERE item_number LIKE \'11-%\' LIMIT 10', function (resultsObject) {
myQuery = JSON.stringify(resultsObject.result.rows);
console.log('Did stringify work?');
console.log(myQuery);
});
console.log(myQuery);
My output:
Info: Start process (3:46:11 PM)
[]
Did stringify work?
[{"item_number":"11-0011"},{"item_number":"11-0012"},{"item_number":"11-1255"},{"item_number":"11-0052"},{"item_number":"11-0060"},{"item_number":"11-1256"},{"item_number":"11-1281"},{"item_number":"11-0659"},{"item_number":"11-0660"},{"item_number":"11-0054"}]
Info: End process (3:46:12 PM)
I think I understand what's happening, the scope of the variable myQuery is set and printed within the runQuery function just fine, but outside of that function it's not being actually set. How do I get around this?
Very new to JavaScript and NodeJS so I hope I'm using the correct terminology.
Thanks in advance!
The empty myQuery has already been consoled before you actually put values into it. This issue is caused by Javascript's Asynchronous mechanism. If you want to do something with the result, you have to use a callback function. Just like what you did when you accessed result from runQuery.
Another way to do it is promise. You can return a promise in some function and use the promise to access result.
If you decide to use promise, here is the code:
function getresult(parameters) {
return new Promise((resolve, reject) => {
runQuery(parameter, resolve, reject);
});
}
Using this function, you passed resolve as callback to runQuery. You do want to add another err callback function to catch err in runQuery. In promise you use reject as err callback.
When you want to do something with the result:
getresult(parameters)
.then((result) => {put your code here. result variable is your result})
.catch((err) => {do whatever with err});
This is not a scope issue. It is a timing issue. The query takes some time to execute. JavaScript is 'non-blocking' meaning it will start an asynchronous process (like doing a DB query - really virtually all I/O operations) and return the result later. In your code you are using a callback that is run once the data becomes available.
So, with that in mind, the way to think about your code is that you are doing things in this order:
1) declaring your function runQuery - this happens first since in JavaScript function declarations are moved to the top of the script they are in (a process called hoisting)
2) your variable myQuery is established and initialized (to an empty array)
3) your query is kicked off by a call to runQuery; this only starts the process
4) your console.log(myQuery) at the end of your script is run
5) some time later the query completes and your callback is called with the data where your other console.log() shows the returned data

How do I properly issue response to post when waiting for async method to complete?

Here's the setup in a module. See, esp., comments marked by ****:
exports.saveWall = function (req, res) {
var status;
mongoClient.connect(connectionString, function (err, db) {
if (err) { return console.dir(err); }
db.collection(pictureWallsCollectionName).insert(
{ _id: req.body.wallId, pictures: req.body.pictures },
function (err, res) {
db.close();
if (err) {
status = 500;
console.dir(err);
}
else {
status = 200;
//*****can't do this here, because res is out of scope!
res.status(status).send(http.STATUS_CODES[status])
console.log('Inserted into the ' + pictureWallsCollectionName + ' collection');
}
});
});
//*****can't do this yet because the above isn't done.
res.status(status).send(http.STATUS_CODES[status])
}
I basically want to call the line res.status(status).send(http.STATUS_CODES[status]) in my callback, but I can't because res.status is null at that point.
All I want to do is respond to a POST, but I am not getting anywhere.
Even though you solved your scope issue (which is awesome), nesting callbacks can get kind of tricky quickly (as you saw). A good way to deal with this is to use promises. The two main packages for promises are Q and Bluebird (with Bluebird being my favorite).
You can also use a package that has already promise-ified mongo calls for you, like promised-mongo
Once you have that all set up, it's just a matter of chaining .then for successive steps, and then sending your response when the promise is resolved.
For a specific example, check out this answer and see if that helps.
Ugh...
It turns out my issue was that "res" was defined both here:
exports.saveWall = function (req, res) {
...and here:
db.collection(pictureWallsCollectionName).insert(...,
function (err, res) {
...so it turns out I could call "res" all along, I was just trying to call the wrong "res" because it got redefined.
On a side note, f*** you, javascript!

How to prevent nested promise from hanging?

The following code works (the user object is written to the console), however the process doesn't exit. I believe one of the promises must not be resolved?
var Promise = require("bluebird");
var mongodb = require('mongodb');
Promise.promisifyAll(mongodb);
mongodb.MongoClient.connectAsync("mongodb://localhost/test")
.then(function(db){
var users = db.collection('users');
return users.findOneAsync({userName: "someuser"});
})
.then(function (result) {
console.log(result);
})
.catch(function(e){
//handle error
});
What is wrong with this code?
MongoDB creates a persistent connection which you're supposed to use for the whole lifecycle of your application.
When you're done with it - close it. That is - call db.close()
If you want to write saner code, use Promise.using and a disposer for making a saner connectAsync which does resource management for you.

Categories