Confused about node-mongodb-native syntax - node.js

I'm just getting into node and mongodb and came across the first obstacle.
I'm walking through a tutorial where the code looks something like this:
var db = new mongo.Db("database", new mongo.Server(host, port, {}));
db.open(function(error){
db.collection("user", function(err, collection){
collection.find({"id":"1"}, function(error, cursor){
cursor.toArray(function(err, users){
if(users.length == 0){
console.log("no such user");
} else if {
console.log("user found: ", users[0]);
}
});
});
});
However the code failed to work saying that users is null. (I do have a code where it inserts entries) Anyway, while trying to figure out what's going on, I've come across the documentation where it uses a synchronous pattern for find instead of using callback to retrieve cursor. The code goes something like this:
var cursor = collection.find({"id":"1"});
In fact, I cannot find anywhere in the documentation where it mentions a usage of find with a callback that returns a cursor. I am really confused. Is the tutorial outdated? And what is wrong with this code?

If users is null, then it's likely that err is indicating what the problem is. Add an if (err) path to your code to log err when it's set.
find can work in both ways that you describe. The callback parameter is optional and if you don't provide it you can use the cursor that's returned instead. See the docs: link.

Related

nodejs execution comes out of order?

I'm adding node.js to an existing site for its "server side Java Script" capabilities, and have been following through several of the tutorials to get a handle on it. ...Of course, as an experienced programmer learning a new thing, I'm experimenting a little beyond what the tutorials might give. So, instead of replacing the effort with every iteration, I've been adding to what the code does in hopes that when I'm done I have one bit of code that exercises all the materials covered.
In doing this I have uncovered a clear example of out-of-order execution that seems to me to be completely unacceptible, but then maybe I'm missing something, which is why I'm posting (though it's also valuable to others who follow that if I'm right, all node.js programmers should know about it).
Here's a link to the tutorial that led me to this. This is the start of it.
When I got to the file-access section, since we were learning how to create and delete files shortly after learning how to populate variable values from the URL, I decided to use a conditional value to delete a newly created or updated file based on what the user had provided in the URL. This seems entirely rational to me!
But, it doesn't work out correctly; even though the code to delete the file occurs AFTER the code to create the file, in fact the deletion occurs before the creation and so, in the end, the file still exists! Perhaps more correctly, an instance of file creation happens after the potential file deletion, even though the order in the code is otherwise. (Note that this is a testing environment, so it's not as if some other user accessed the system causing a creation without the deletion condition being met.) This is easily repeatable.
Here's the code:
var http = require("http");
var dt = require("./firstmodeule.js");
var url = require("url");
var fs = require("fs");
var fn = "index.html";
var log = "nodejs.log";
http.createServer(function (req, res)
{
res.writeHead(200, {"Content-Type": "text/html"});
res.write("<p>New current Date & Time: "+dt.myDateTime()+"<br>");
res.write(req.url+"<br>"); // This captures the right hand of the URL.
var q = url.parse(req.url, true).query;
var txt = q.year + " " + q.month;
res.write(txt+"</p>");
res.write("<p></p>");
fs.appendFile(log, dt.myDateTime()+" "+txt+"\n", function (err)
{
if (err) throw err;
console.log("saved?");
});
fs.readFile(fn, function(err, data)
{
fs.writeFile("delable.index", data, function(err)
{
if (err)
{
throw err;
} else {
console.log("wrote to delable.index");
}
});
res.write(data);
res.end();
});
if (q.month = "Jan")
{
fs.unlink("delable.index", function (err)
{
if (err)
{
throw err;
} else {
console.log("Deleted delable.index");
}
});
}
//res.end(); // End CANNOT be here if we"re doing a res.write(data);
}).listen(8080);
Of course you can get the tiny bit of code for firstmodule.js from the cited tutorial - or just delete it since it has no bearing on this.
Here's an example of the URL:
http://MySite:8080/?year=2020&month=Jan
Here's an example of the output I get:
$ node example.js
Deleted delable.index
saved?
wrote to delable.index
Deleted delable.index
saved?
wrote to delable.index
Contrary to the order of the code, we get the deleted part first!
OK, so, what gives? Does node.js just do things in whatever order it wants?
For anyone curious, this is all extremely current code as of this date. The OS is Fedora 28 downloaded in the last few days, and the node package is nodejs-8.11.4-1.fc28.x86_64.
Change fs.appendFile to fs.appendFileSync and change fs.readFile to fs.readFileSync and then the functions will be synchronous and hence in the order of execution to match the order of your code.

How to handle known errors that have no reason to be thrown

I am very aware of the problems with using uncaughtException in my code. I am also aware that the domains module is being deprecated so I do not want to use that. My question is what to do when I encounter an error that should not happen. For instance, if using mongo db and mongoose the following code example is give:
var kitty = new Cat({ name: 'Zildjian' });
kitty.save(function (err) {
if (err) {
console.log(err);
} else {
console.log('meow');
}
});
Here there is, what I assume is an inexplicable error. It is caught, but only uses console.log to log the error. Clearly more would have to happen to inform the user there is a problem, but I am wondering what should happen to the rest of the application.
Should it shutdown? Should something else happen? I have a good number of cases where I can catch errors like this, but if they happen they represent some very weird situation where something like the database has failed, or something else from another library has failed for no explicable reason and
I suggest you to return a json to your app showing the results of operation. Example:
if(err) {
res.status(500).json({saved: false, errormsg: 'Cannot save to database'});
} else {
res.json({saved: true, errormsg: null});
}
Handle the response in your app and show to the user that some bad think happened.

Mongoose - save() doesn't actually save, but doesn't give an error either

I know there are a lot of threads with this problem, but none of the resolutions presented there work for me, often because the problem is too specific. Before I explain my problem, here is my code:
User.findOne({authId: req.user.authId}, function(err, user){
if(err) console.error(err);
for(var i = 0; i<user.bot.messages.length; i++){
if(user.bot.messages[i].name === req.body.commandName){
console.log('found it');
user.bot.messages[i].description = req.body.commandDescription;
}
}
user.save(function(err){
if(!err){
console.log('saving user');
}
});
});
What this code should do is update the description of a message after the user submits a form with said description. Usually when updating with mongoose I just use findOneAndUpdate() but that wouldn't work in this case, since it only accepts dot notation and I don't know beforehand which message is being updated.
Still, this should work as well, right? The multiple console.log() statements are just for debugging. The thing is though, I see all of those statements in the console when submitting the form, so I really don't know what the problem is in this case.
It just doesn't save, but I'm not getting any errors either.
I just found this in the mongoose docs. But how am I supposed to use markModified() if I don't know the exact path beforehand?

MongoDB NodeJS driver, how to know when .update() 's are complete

As the code is quite large to posted in here, I append my github repo https://github.com/DiegoGallegos4/Mongo
I am trying to use de NodeJS driver to update some records fulfilling a criteria but first I have to find some records fulfilling another criteria. On the update part, the records found and filter from the find operation are used. This is,
file: weather1.js
MongoClient.connect(some url, function(err,db){
db.collection(collection_name).find({},{},sort criteria).toArray(){
.... find the data and append to an array
.... this data inside a for loop
db.collection(collection_name).update(data[i], {$set...}, callback)
}
})
That´s the structure used to solve the problem, relating when to close the connection , it is when the length of the data array equals the number of callbacks on the update operation. For more details you can refer to the repo.
file: weather.js
On the other approach, Instead of toArray is used .each to iterate on the cursor.
I've looked up for a solution to this for a week now on several forums.
I've read about pooling connections but I want to know what is my conceptual error on my code. I would appreciate a deep insight on this topic.
The way you pose your question is very misleading. All you want to know is "When is the processing complete so I can close?".
The answer to that is you need to respect the callbacks generally only move through the cursor of results once each update is complete.
The simple way without other dependencies is to use the stream interface suported by the driver:
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/data',function(err,db){
if(err) throw err;
coll = db.collection('weather');
console.log('connection established')
var stream = coll.find().sort([['State',1],['Temperature',-1]])
stream.on('err',function(err) {
throw err;
});
stream.on('end',function() {
db.close();
});
var month_highs = [];
var state = '';
var length = 0;
stream.on('data',function(doc) {
stream.pause(); // pause processing documents
if (err) throw err;
if (doc) {
length = month_highs.length
if(state != doc['State']){
month_highs.push(doc['State']);
//console.log(doc);
}
state = doc['State']
if(month_highs.length > length){
coll.update(doc, {$set : {'month_high':true} }, function(err, updated){
if (err) throw err;
console.log(updated)
stream.resume(); // resume processing documents
});
} else {
stream.resume();
}
} else {
stream.resume();
}
});
});
That's just a copy of the code from your repo, refactored to use a stream. So all the important parts are where the word "stream" appears, and most importantly where they are being called.
In a nutshell the "data" event is emitted by each document from the cursor results. First you call .pause() so new documents do not overrun the processing. Then you do your .update() and within it's callback on return you call .resume(), and the flow continues with the next document.
Eventually "end" is emitted when the cursor is depleted, and that is where you call db.close().
That is basic flow control. For other approaches, look at the node async library as a good helper. But do not loop arrays with no async control, and do not use .each() which is DEPRECATED.
You need to signal when the .update() callback is complete to follow a new "loop iteration" at any rate. This is the basic no additional dependancy approach.
P.S I am a bit suspect about the general logic of your code, especially testing if the length of something is greater when you read it without possibly changing that length. But this is all about how to implement "flow control", and not to fix the logic in your code.

Converting object returned by MongoDB into bar?

I think this is a very simple question? I am a beginner trying to learn mongo with node.
Once I have saved something to a collection, how can I pull it out in simple var format?
db.highschools.save({
hsid :10,
name :"Johnson High School",
location:"San Diego, CA"
});
I simply want to store a var as 'Johnson High School'.
My failed attempts that have returned undefined are as follows...
var hsName = db.highschools.find({hsid:10}).name;
var hsName = db.highschools.find({hsid:10}).name.str;
Pretty sure I'm missing the big picture here, would someone please be kind enough to help me figure this out?
Use findOne instead:
var hsName = db.highschools.findOne({hsid:10}).name;
Also, note that this is a Mongo script, not a NodeJS script.
You'll need to make it async when you write the logic in NodeJS.
db.collection('students', function(err, collection) {
collection.findOne({hsid:10}, function(err, student) {
if (err) { throw err; }
console.log(student.name);
});
});
If you're confident that there should be only one result, then you can use the shortcut method findOne which simply calls find internally with a limit of one. If you were to use find, it returns an array of matches.

Resources