Need help using MongoDB with Heroku & Node, Express - node.js

My project goal is to make a checklist-like web app where the user can see what's in the database and also update what's inside it.
Database is simple. Just listing favorite things. Eg {"favorite":"Pie"},{"favorite":"Kitty"}
So far I've figured out how to connect to the database(MongoHQ) and show a single element of data. I've been trying for hours but I'm stumped on:
Getting the html file to write whatever data is in the database.
Writing the Post form to write to the database.
Please share some insights!
Here's my code.
.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>
<h1>Notepad</h1>
<p>Favorite things: {{favorite}}</p>
<!-- {% for favorite in doc %} <-this doesn't work!
<p>Favorite things: {{favorite}}</p>
{% endfor %}
-->
</div>
</body>
</html>
web.js
var express = require('express');
var path = require('path');
var fs = require('fs');
var http = require('http');
var mongo = require('mongodb');
var MongoClient = mongo.MongoClient;
var Server = require('mongodb').Server;
var mongoUri = "mongodb://id:pass#ds------.mongolab.com:-----/heroku_app------";
var cons = require('consolidate');
var app = express(express.logger());
app.engine('html', cons.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
app.set('port', process.env.Port || 8080);
app.use(express.bodyParser());
var mydatabase = null;
var myCollection = null;
MongoClient.connect(mongoUri, function(err, db){
if(!err){
console.log("We are connected to mongo_lab!");
}
mydatabase = db;
mydatabase.createCollection('test2', function(err, collection){});
myCollection = mydatabase.collection('favorites');
//myCollection.insert({'favorite':'Blueberries'}, {w:1}, function(err, result){});
});
var mongoclient_server = new MongoClient(new Server('localhost', 27017));
function errorHandler(err, req, res, next){
console.error(err.message);
console.error(err.stack);
res.status(500);
res.send("Fix the dam Error!");
}
app.use(errorHandler);
app.get('/notepad', function(req, res, next){
MongoClient.connect(mongoUri, function(err, db){
mydatabase.collection("favorites").find().toArray(function(err, doc){
if(err) throw err;
console.log(doc);
res.render('notepad', doc[0]);
});
});
});
var htmlfile = "index.html";
app.get('/', function(request, response) {
var html = fs.readFileSync(htmlfile).toString();
response.send(html);
});
var port = process.env.PORT || 8080;
app.listen(port, function() {
console.log("Listening on " + port);
});
//mongoclient_server.open(function(err, mongoclient_server){ <--if I use this, heroku crashes
// if(err) throw err;
// app.listen(port);
//});

You're passing data from doc[0] as locals to your notepad view, so basically notepad locals will be what is in doc[0].
In your call to res.render(), you should specify that your documents reside in the doc local, like this:
res.render('notepad', {
doc: doc
});
This way your {% for ... %} will work.
Docs for res.render

Related

Pass existing data to different view

While in / view, I get documents from mongodb and create a list item for each document that only shows the date and the first few words. I want to be able to click on each list item to go to a new page, /view, to see the rest of that particular document.
To do this, I believe I need to pass item between / and /view, then access the properties of item there. How do I do this with the pagelist function (or without it)?
index.js:
var express = require('express');
var exphbs = require('express-handlebars');
var bodyParser = require('body-parser');
var app = express();
var hbs = exphbs.create({
helpers: {
message: function() {return 'Welcome!';},
doc: function() {return "Something went wrong.";}
}
});
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var util=require('util');
const url = 'mongodb://localhost:27017/users';
const dbName = 'users';
var db;
MongoClient.connect(url, function(err, client) {
assert.equal(null, err);
console.log("Connected successfully to server");
db = client.db(dbName);
db.collection("reviewYelp2", { }, function(err, coll) {
if (err != null) {
console.log(err)
db.createCollection("reviewYelp2", function(err, result) {
assert.equal(null, err);
});
}
db.ensureIndex("reviewYelp2", { document: "text"}, function(err, indexname) {
assert.equal(null, err);
});
});
});
app.get("/", function(req, res) {
res.render('search');
});
app.get("/view", function(req, res) {
// NEED TO BE ABLE TO ACCESS CLICKED ITEM HERE
res.render('viewItem', {
// Change to access item.text when I have access to item
helpers: {
doc: function() {return "Viewing doc...";}
}
});
});
app.post("/", function(req, res) {
db.collection('reviewYelp2').find({
text: new RegExp(req.body.query)
}).sort({date: 1}).toArray(function(err, items) {
res.render('search', {
helpers: {
message: function() {return pagelist(items);}
}
});
})
});
function pagelist(items) {
result = "<ul>";
items.forEach(function(item) {
// Grab only first 10 words of text
textSlice = item.text.split(" ");
textSlice = textSlice.slice(0, 5);
text = textSlice.join(" ");
str = "<li class="+item._id+"><a href='/view'>" + item.date + " " + text + "...</a></li>";
result = result + str;
});
result = result + "</ul>";
return result;
}
app.listen(3000, function() {
console.log("App listening on localhost:3000");
});
search.handlebars:
<!DOCTYPE html>
<html>
<body>
<form method="post">
<input type="text" size="80" name="query" />
<input type="submit" value="Search" class="submitButton" />
{{{ message }}}
</form>
</body>
</html>
viewItem.handlebars:
<!DOCTYPE html>
<html>
<body>
<button onclick="window.history.back()">Go back to list</button>
{{{ doc }}}
</body>
</html>
This is problematic because http is fundamentally stateless — that is each request to the server is it's own thing. You can come up with schemes involving cookies or local storage, but I think a simpler approach is both better and more common.
A simpler idea is to have a route that takes some sort of id parameter:
app.get("/view_detail/:itemID", function(req, res) {
var item = req.params.itemID
// lookup detail about item based on itemID
res.render('viewItem', {
// send data
});
});
Now on index you can have a list of links that look like :
/view/878743 (or whatever scheme you have for db keys)
/view/36764e

Getting all the images uploaded from MongoDB

I made a upload image to a document and saved the path to the MongoDB , While retrieving the Image, It is showing only the current image which is being uploaded. I want to show all the images which is uploaded to the database. Please help me to display all the images from the Data base.
Thank you in advance :)
var express = require('express'); //Express Web Server
var busboy = require('connect-busboy'); //middleware for form/file upload
var path = require('path'); //used for file path
var fs = require('fs-extra'); //File System - for file manipulation
var mongoose = require('mongoose');
var handlebars = require('handlebars');
var mongoClient = require('mongodb').mongoClient;
var objectId = require('mongodb').ObjectId;
var app = express();
app.use(busboy());
app.use(express.static(path.join(__dirname, 'public')));
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost:27017/postname');
/* ==========================================================
Create a Route (/upload) to handle the Form submission
(handle POST requests to /upload)
Express v4 Route definition
============================================================ */
app.set('view engine', 'hbs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.static(__dirname + '/public'));
//You can import your schema like this
const Name = require('./name');
app.get('/', function(req, res, next) {
res.render('index',{'title': 'New post app'});
});
//I have changed your route since it seems to be clashing with the above
app.post('/save' ,function (req, res, next) {
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function(fieldname, file, filename, done){
console.log("Uploading" + filename);
//path where the file is being uploaded
fstream = fs.createWriteStream(__dirname + '/public/uploads/' + filename);
var dirname = path.join( 'uploads/' + filename);
file.pipe(fstream);
fstream.on('close', function(){
console.log("Upload Success" + filename);
let name = new Name({
path: dirname
});
name.save((err)=>{
if(err) throw err;
console.log(`saved : ${name}`);
res.redirect('/profile');
call(dirname);
});
});
});
});
function call(dirname){
Name.findOne({path: dirname}, (err, result) =>{
if(err) throw err;
var imgpath = result.path;
console.log("Saved check" + imgpath);
app.get('/profile', (req, res) =>{
res.render('profile',{
photo: req.result,
result : imgpath
});
});
});
}
var server = app.listen(3030, function() {
console.log('Listening on port %d', server.address().port);
});
My name.js file Mongoose Schema
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let compileSchema = new Schema({
path: String
});
let Compile = mongoose.model('Compiles', compileSchema);
module.exports = Compile;
Views File to display the image
<html>
<head>
<title>User Profile</title>
</head>
<body>
<h1>Welcome</h1>{{result}}<br><br>
<img src="{{result}}" height="180" width="250">
</body>
</html>
You are using findOne which only retrieves one object from the database. So if you want to retrieve all the images your code should be something like this :
var express = require('express') // Express Web Server
var busboy = require('connect-busboy') // middleware for form/file upload
var path = require('path') // used for file path
var fs = require('fs-extra'); // File System - for file manipulation
var mongoose = require('mongoose')
var handlebars = require('handlebars')
var mongoClient = require('mongodb').mongoClient
var objectId = require('mongodb').ObjectId
var app = express()
app.use(busboy())
app.use(express.static(path.join(__dirname, 'public')))
mongoose.Promise = global.Promise
mongoose.connect('mongodb://localhost:27017/postname')
/* ==========================================================
Create a Route (/upload) to handle the Form submission
(handle POST requests to /upload)
Express v4 Route definition
============================================================ */
app.set('view engine', 'hbs')
app.set('views', path.join(__dirname, 'views'))
app.use(express.static(__dirname + '/public'))
// You can import your schema like this
const Name = require('./name')
app.get('/', function (req, res, next) {
res.render('index', {'title': 'New post app'})
})
// I have changed your route since it seems to be clashing with the above
app.post('/save' , function (req, res, next) {
var fstream
req.pipe(req.busboy)
req.busboy.on('file', function (fieldname, file, filename, done) {
console.log('Uploading' + filename)
// path where the file is being uploaded
fstream = fs.createWriteStream(__dirname + '/public/uploads/' + filename)
var dirname = path.join( 'uploads/' + filename)
file.pipe(fstream)
fstream.on('close', function () {
console.log('Upload Success' + filename)
let name = new Name({
path: dirname
})
name.save((err) => {
if (err) throw err
console.log(`saved : ${name}`)
res.redirect('/profile')
// removed call(), no need for it
})
})
})
})
app.get('/profile', (req, res) => {
// get all documents in the db by using find with no conditions
Name.find({}, (err, results) => {
if (err) throw err
var images = []
for (var result of results) {
images.push(result.path)
}
res.render('profile', {
images: images
})
})
})
var server = app.listen(3030, function () {
console.log('Listening on port %d', server.address().port)
})
And in the views you should loop through the images to display them, i believe you are using handlebars so the view should be something like this :
<html>
<head>
<title>User Profile</title>
</head>
<body>
<h1>Welcome</h1>
{{#each images}}
<img src="{{this}}" height="180" width="250">
{{/each}}
</body>
</html>

TypeError: mongoclient.db is not a function

Please Someone response me with what's wrong with this code...
When I run the program ,I find the bug in mongodb part.
The error in
var db = mongoclient.db();
var express = require('express'),
app = express(),
cons = require('consolidate'),
MongoClient = require('mongodb').MongoClient,
Server = require('mongodb').Server;
app.engine('html', cons.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
var mongoclient = new MongoClient(new Server("localhost", 27017), {native_parser: true});
var db = mongoclient.db();
app.get('/', function(req, res){
// Find one document in our collection
db.collection('hello_combined').findOne({}, function(err, doc) {
if(err) throw err;
res.render('hello', doc);
});
});
app.get('*', function(req, res){
res.send('Page Not Found', 404);
});
mongoclient.open(function(err, mongoclient) {
if(err) throw err;
app.listen(8080);
console.log('Express server started on port 8080');
});
I'm only showing you this code because It shows how to connect to a database.
I didn't need that Server = require('mongodb').Server; section that you have.
The code shows how to
require monogodb to get the Driver for mongodb in Node. require("mongodb").MongoClient
then you connect using MongoClient.connect. In my case Im connecting to my allready existing database called crunchbase
then you can query the database I find the field with the name of category_code and the value biotech in the collection companies.
var MongoClient = require("mongodb").MongoClient;
MongoClient.connect("mongodb://localhost:27017/crunchbase", function(err, db){
console.log("connected to the DB");
var query = {"category_code" : "biotech"};
db.collection("companies").find(query).toArray(function(err, docs){
docs.forEach(function(doc){
console.log(doc.name + " is a " + doc.category_code + "company")
});
db.close()
})
})

Render document field as HTML

I'm creating my first sample code using NodeJS, Express, MongoDB and Swig. It's a small blog application and I'm trying to render the existing posts, however, the post body contains HTML tags and they are printed as text.
How can I render them as HTML?
Here is my view (main.html):
<p>
<h3>{{title}}</h3>
<h6><i>{{postedAt}}</i></h6>
</p>
<p>
{{content}}
</p>
And here is the app.js:
var express = require('express');
var cons = require('consolidate');
var app = express();
var MongoClient = require('mongodb').MongoClient;
var Server = require('mongodb').Server;
app.engine('html', cons.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
var mongoClient = new MongoClient(new Server('localhost', 27017,
{ 'native_parser' : true }));
var db = mongoClient.db('blog');
// Base URL - Show posts
app.get('/', function (request, response) {
var cursor = db.collection('posts').find().sort({'postedAt': 1});
cursor.each(function (err, doc) {
if (err) throw err;
if (doc == null) {
return db.close();
}
response.render('main', doc);
});
});
app.get('*', function (request, response) {
response.send('Page not found', 404);
});
mongoClient.open(function (err, client) {
if (err) throw err;
app.listen(8080);
console.log('Express started listening on port 8080');
});
Swig HMTL-escapes all variables by default.
If you’re sure the content in question is safe (i.e. the HTML doesn’t include malicious JavaScript), then you can turn off HMTL-escaping using the safe filter:
<p>
<h3>{{title}}</h3>
<h6><i>{{postedAt}}</i></h6>
</p>
<p>
{{content|safe}}
</p>

Display basic HTML file in NodeJS and ExpressJS

I am using NodeJS and ExpressJS to implement a RESTful API server for a simple backend. I am also using BackboneJS to render views in the front. Therefore, right now I have a single index.html file that I want to render when the client sends a /GET to the '/' route. This is what I have so far:
var express = require('express');
var app = express();
app.use(express.bodyParser());
var mongo = require('mongodb');
var mongoose = require('mongoose');
var Server = mongo.Server,
DB = mongo.Db,
BSON = mongo.BSONPure;
var server = new Server('localhost', 27017, {auto_reconnect: true});
db = new DB('mydb', server, {safe: true});
db.open(function(err, db) {
if(!err) {
console.log("Connected to 'mydb' database");
db.collection('items', {safe:true}, function(err, collection) {
if (err) {
console.log("Creating collection 'items'");
}
});
}
});
var port = process.env.PORT || 3000;
app.engine('.html');
var listItems = function(req, res){
db.collection('items', function(err, collection){
var items = collection.find();
console.log(items);
res.send(items);
});
}
var itemDetails = function(req, res){
}
var deleteItem = function(req, res){
}
var createItem = function(req, res){
}
var updateItem = function(req, res){
}
var routeHome = function(req, res){
// What can I do here to render a plain .html file?
}
app.all('*', function(req, res, next){
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Content-Type", "application/json");
next();
});
app.get('/', routeHome);
app.get('/items', listItems);
app.get('/items/:id', itemDetails);
app.del('/users/:id', deleteItem);
app.post('/users', createItem);
app.put('/users/:id', updateItem);
app.listen(port);
console.log("Server started up on port " + port);
As you can see I have everything set up except I cannot figure out how to send a regular .html file to the client. I do not need a rendering engine because Backbone is doing all that for me. I just want to get index.html to go to the client.
How about just using the express.static middleware? Since you're using Backbone, you might have the need for sending static JS files as well:
app.use(express.static(__dirname));
Place that somewhere before your other routes. It will try and find files requested in __dirname (the directory where your app.js file resides, but you can of course change the location where the middleware will try and find files), including index.html.
Step One, Remove app.engine(".html"),
Step Two:
var routeHome = function(req, res){
// Do What Ever
res.sendFile("index.html",function(err){ // Transfer The File With COntent Type Text/HTML
if(err){
res.end("Sorry, Error.");
}else{
res.end(); // Send The Response
}
})
}

Resources