Reputation: 1189
Hi newbie here, with express i tried the .toArray method using the video database on localhost. This code works fine, i was able to display the data using handlebars as my template engine, each data shows the title, year and imdb in a bordered container:
MongoClient.connect('mongodb://127.0.0.1:27017', function(err, database){
assert.equal(null,err);
console.log('Successfully connected to MongoDB');
var db = database.db('video');
router.get('/', function(req,res){
db.collection('movieDetails').find({}).toArray(function(err,result){
res.render('home', {
title: 'Movies',
movieDetails: result
});
database.close();
});
});
});
however, using cursor method, i see no data but only the borders and the labels, And i get this error on bash shell "Can't set headers after they are sent." this is the code:
MongoClient.connect('mongodb://127.0.0.1:27017', function(err, database){
assert.equal(null,err);
console.log('Successfully connected to MongoDB');
var db = database.db('video');
router.get('/', function(req,res){
var query = {};
var cursor = db.collection('movieDetails').find(query);
cursor.forEach(
function(result){
res.render('home',{
title: 'Movies',
movieDetails: result
});
},
function(err){
assert.equal(err, null);
return database.close();
}
);
});
});
This is the code of my homepage using handlebars template engine:
{{#each movieDetails}}
<div class="movie_data">
<h5>{{this.title}}</h5>
<p><strong>Year:</strong> {{this.year}} <strong>Imdb:</strong> {{this.imdb}}</p>
</div>
{{/each}}
Need help, i can't seem to figure out how to display the data using the cursor method, thanks!
Upvotes: 0
Views: 1878
Reputation: 105
I had this same problem trying to use forEach()
and did a lot of looking for an answer but mostly the reply is "just use toArray()
". But I wanted to use the "streaming batch of docs" that forEach()
gives better efficiency right? wrong...
I see your using the same data from mongoUni, me too, I put a question up there and this is a breakdown of the best answer...
The efficiency only works for huge amount of results 250,000 for example but typically when rendering a template we may only need 50.
Using forEach()
to return 50 results as actually less efficient than toArray()
as it forces the cursor to do the iteration and array building.
toArray()
basically implements an "async loop" which "iterates" the cursor content for you and only returns once that async iteration is complete. For a small batch results (using limit()
in the query) toArray()
is the best and really the only option.
Upvotes: 1
Reputation: 4869
this should work as you expect
router.get('/', function(req,res){
var query = {};
db.collection('movieDetails').find(query).toArray(function(err, result){
res.render('home',{
title: 'Movies',
movieDetails: result
});
});
});
Upvotes: 1
Reputation: 171
There is a semantic difference between the two code snippets you have shared. The culprit is in the result handler.
In the first handler (the one as a callback into the toArray
function) tells the library to give you the results in the form of an array. When you ask the express server to send a response, you are passing the whole array stored (the reference is stored in the result
variable).
In the second handler, where you are using the cursor method, the forEach
call tells the Mongo library to execute the callback for each element inside the cursor results. This means that if your query returns 5 movies, the callback will be executed 5 times. This also means that the res.render
will try to execute 5 times. This will lead to the error you are seeing, as on the second iteration, the res
instance you have a reference to would have already been sent.
As your handler inside Handlebars expects an array of movies, and the response you gave it was a single movie instance (remember the forEach
method will pass each item of the collection individually to the callback inside the result
parameter), your page won't render correctly.
I hope this helps you out. Good luck :)
Upvotes: 3