Using Nodejs & Expressjs to Upload and save Image Files into MongoDB (Part 2/3)

1101-sdt-mongoThis is a follow-on to Part 1, an introductory post

This example will use the Expressjs templating engine. Expressjs can be a deep and mind boggling domain but we’ll use only two of its key features, routes and views.

This example will NOT use mongdb GridFS. In the interests of keeping this as simple as possible, we’ll limit our image file size to < 2MB and avoid helper libraries that obfuscate what’s going on.

So assuming you have nodejs working you can stub out a templated app. I’m going to use Express Application Generator to get a directory structure and some file templates going. I’ll also install nodemon, a useful utility which restarts the nodejs service each time you save a file change.

sudo npm install express-generator nodemon -g

I’m choosing to use the ejs templating engine instead of the default Jade engine. If you’re unfamiliar with Jade, it looks weird. A bit like going straight to Coffeescript and bypassing Javascript.

express --ejs --git --testdir

Install two NPM packages

install mongodb multer --save

You may want to run this to make sure packages and dependencies are up to date.

npm install

Now start your node service from within your testdir and you should be able to access it from your browser with http://localhost:3000 (or whatever port it starts on)

nodemon bin/www

Only two files are really needed for this example,

  1. routes/index.js
  2. views/index.ejs

Open each in your code editor and we’ll start with views/index.ejs. This is the minimum HTML necessary to get a ‘choose file’ button and file selector going. It also includes a text field for some user entered meta data.

<form action="/uploadpicture" method="POST" enctype="multipart/form-data">
<input type="file" name="picture" accept="application/x-zip-compressed,image/*">

<input class="form-control" type="text" name="description" placeholder="Description or Message">

<input class="btn btn-primary" type="submit" value="submit">
</form>

Save this file and goto the routes/index.js

We’re going to create two routes. You’ll want it to look something like this,

var express = require('express')
   , router = express.Router()
   , MongoClient = require('mongodb').MongoClient
   , ObjectId = require('mongodb').ObjectId
   , fs = require('fs-extra')
   // Your mLabs connection string
   , url = 'mongodb://username:password@yourinstanced.mlab.com:29459/yourdb'
   , multer = require('multer')
   , util = require('util')
   , upload = multer({limits: {fileSize: 2000000 },dest:'/uploads/'})

// Default route http://localhost:3000/
router.get('/', function(req, res){ res.render('index'); });

// Form POST action handler
router.post('/uploadpicture', upload.single('picture'), function (req, res){

if (req.file == null) {
  // If Submit was accidentally clicked with no file selected...
  res.render('index', { title:'Please select a picture file to submit!'); });
} else {

MongoClient.connect(url, function(err, db){
   // read the img file from tmp in-memory location
   var newImg = fs.readFileSync(req.file.path);
   // encode the file as a base64 string.
   var encImg = newImg.toString('base64');
   // define your new document
   var newItem = {
      description: req.body.description,
      contentType: req.file.mimetype,
      size: req.file.size,
      img: Buffer(encImg, 'base64')
   };

db.collection('yourcollectionname')
   .insert(newItem, function(err, result){
   if (err) { console.log(err); };
      var newoid = new ObjectId(result.ops[0]._id);
      fs.remove(req.file.path, function(err) {
         if (err) { console.log(err) };
         res.render('index', {title:'Thanks for the Picture!'});
         });
      });
   });
   };
}); 

This should be about all you need to get a basic uploader running…

One important note here is that we’re converting the binary image file (jpg) into a text string that is base64 encoded. This is not the nodejs default (utf-8). The reason for this is not well documented according to Google but will become apparent in the next post.

The next post will examine how to extract these image files from mongodb and serve them up over http.

Advertisements

Free Nodejs & MongoDB Hosting at Heroku & mLabs (Part 1/3)

Node.js has been all the rage for several years now. The momentum and traction since ~2014 seems to have caught the ‘enterprise community’ off guard. Data center penetration is growing and raising alarms with Chief Information and Computer Security Officers, mostly concerned over source code pollution at GitHub and NPM. Justified or not, there is still no credible evidence based answer to this concern.

As developers continue to pile into this stack, more are asking where to host their prototype or hobby apps. Preferably free, or at least modestly priced.

I’ve been using and recommending Heroku for a few years. Not that it’s the best, cheapest or most performant but because it’s the one I’m most familiar with.

I’ve been meaning to get to grips with Google’s Cloud hosting of Nodejs, but have yet to find the time. Also, price transparency remains a deterrent.

herokucaptureHeroku was around long before all the nodejs excitement started. Founded ~2007 I think.

As has the other critical piece of infrastructure – free MongoDB hosting at mLab.

mLabs is closely integrated into Heroku as an ‘add-on’ so separate registration is not required.

Heroku dashboard serves as the portal to manage your nodejs instance or Dyno as Heroku calls it (not to be confused with a Slug, but I am) and your mongodb collections.

Hclourflarecaptureeroku and mLabs are now wholly owned subsidiaries of Salesforce.com and both host their offerings on Amazon AWS S3.

A third piece of crucial free infrastructure is DNS hosting, robust Content Delivery Networking and SSL encryption.

This too can be had for free by hobbyists and developers via Cloudflare.

It’s been a well kept secret for a long time now.

So what we have is,

Free Nodejs & MongoDB Hosting = Heroku + mLabs + Cloudflare

All you need to get these three pieces up and running is an email address and about a half hour (probably more if you need DNS to propagate).

Fast forward and you’ll find the Heroku Documentation is pretty clear and will get your developer tool chain installed (Heroku CLI and MongoDB Shell) and your first test app deployed with Git.

In the next post we’ll see how to get a simple app running that allows users to upload an image file and store it in mongodb.

The running example is here.