Sessions with node.js / Express – TypeError: Cannot set property ‘X’ of undefined

First off, to enable sessions in node.js with Express, add the following lines to the app config call:

app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat" }));

And that will just do it – super easy.

If you run into a 500 error “Cannot set property X of undefined” it means you placed those two lines below app.use(app.router). It is important that app.use(app.router) is BELOW in your configuration function.

Also, to make sure your session variables are available in jade templates (including layout), use dynamic helpers included with Express:

app.dynamicHelpers({
  session: function(req, res){
    return req.session;
  }
});

In your jade template, simply call session variable like any other variable:

p#id My session var: #{session.var_name}

Mongo update/remove multiple fields

To remove fields from documents in a collection use:

db.test.update({data:{$exists:true}},{$unset:{data:1}},{multi:1});

Or, if you want to add new fields, use set:

db.test.update({data:{$exists:false}},{$set:{data:"your value"}},{multi:1});

Set “multi” to 1 if you want to update/remove fields in all documents that match the criteria.

Using variables in Jade with node.js (substring in jade)

Another funny issue I ran into: apparently jquery can not find elements by ID (#) if the ID string starts with a hashtag (#). In my case, I was using IDs generated from twitter hashtags, and as you know hashtags start with #

So, using $(‘p##myhashtag’).html() did not work. What I could do, is to change the ID of the element and remove the # from the ID. But how do you do it with jade?

That’s when variable support in jade comes in handy! You can manipulate your data right in jade templates using regular javascript. Here’s a snippet that removes hashtag (first character in your string):

    - var st = hashtag
    - var len = st.length
    - var myst = st.substr(1,len)
    p(id=myst)

Tabbed navigation with jade and node.js

I was curious to see if it’s possible to create tabbed navigation and pass current URL parameter to jade from node.js.

It is in fact doable and fairly easy.

In your node.js server, make sure to pass the current URL variable to the your template:

app.get('/users', function(req, res){
  controller.getUsers( function(error, userData){
     res.render('users.jade',{ locals: {
   	users:userData,
   	currentURL:'/users/' 
        }
     });
  });
});

Then, in your jade template, use the conditionals to check for current URL:

div#nav
      ul
        li 
          if(currentURL == '/trends/')
            a(href='/trends/').current Trends
          else
            a(href='/trends/') Trends
        li
          if(currentURL == '/users/')
             a(href='/users/').current Users
          else
             a(href='/users/') Users
        li
          if(currentURL == '/seeds/')
             a(href='/seeds/').current Seeds 
          else
             a(href='/seeds/') Seeds

And here’s a bonus CSS to create nice tabs as your top nav:

#nav ul{text-align:left;border-bottom:1px solid #ccc; 
list-style-type:none;padding:10px 10px;}
#nav ul li{display:inline;}
#nav ul li a{font-weight:bold;border:1px solid #ccc; 
text-decoration:none;padding:10px 20px;
border-bottom:none;margin-right:5px;
margin-bottom:1px;background-color:#eee}
#nav ul li a.current{background-color:#fff;
border-bottom:1px solid #fff;}
#nav ul li a:hover{color:#000;background-color:#eee;}

And that should create a nice nav bar looking like this:

Map Reduce with Node.js and Mongo

Working on my pet project I ran into an issue where the data coming for mongo needed to be prepped for client-side view.

Traditionally, if it was an RDBMS, we could use a “group by” query.

In Mongo, we either have to use the dev release 2.1 that includes the aggregation framework (and then make sure that mongo driver for node.js supports aggregate commands), or use recommended map-reduce approach with stable mongo release.

I tried running a “group” command with mongo 2.1.1, but something didn’t quite work. So then I went for an alternate approach – writing a map-reduce function.

My data set looks like this (hashtags with dates and counters):
{ “count” : 1, “tag” : ” #style”, “tag_date” : “6/20/2012” }
{ “count” : 1, “tag” : ” #centralpark”, “tag_date” : “6/20/2012” }
{ “count” : 1, “tag” : ” #tisch”, “tag_date” : “6/20/2012” }
{ “count” : 2, “tag” : ” #dogs”, “tag_date” : “6/20/2012” }
{ “count” : 1, “tag” : ” #familytime”, “tag_date” : “6/20/2012” }
{ “count” : 1, “tag” : ” #rhonyc”, “tag_date” : “6/20/2012” }
{ “count” : 5, “tag” : ” #believe”, “tag_date” : “6/20/2012” }
{ “count” : 1, “tag” : ” #blogher12″, “tag_date” : “6/20/2012” }
{ “count” : 1, “tag” : ” #youthinkwerekidding”, “tag_date” : “6/20/2012” }
{ “count” : 1, “tag” : ” #pokemonconquest”, “tag_date” : “6/20/2012” }

And I need it to look like this:

{tag: {date:count}, {date:count} … }

In other words, have all dates and counters aggregated for each tag.

Here’s the map-reduce functions:

And here’s how we call it from the app:

Note: ‘inline’ parameter MUST be specified

And the results returned from the DB:

{ “_id” : “#10thingsilove”, “value” : { “value” : [ { “tag_date” : “6/21/2012”, “count” : 1 }, { “tag_date” : “6/22/2012”, “count” : 11 }, { “tag_date” : “6/25/2012”, “count” : 2 } ] } }
{ “_id” : “#10worstfeelings”, “value” : { “value” : [ { “tag_date” : “6/25/2012”, “count” : 1 }, { “tag_date” : “6/26/2012”, “count” : 3 } ] } }

Great resources that helped me make this work:
http://benbuckman.net/tech/12/06/understanding-mapreduce-mongodb-nodejs-php-and-drupal
http://cookbook.mongodb.org/patterns/pivot/

Node.js http request for favicon.ico

AS I was debugging my test node app, I noticed that every http request was sent as actual 2 requests:

– data request (came back with status 200)
– favicon.ico file request (came back with 400, when I hit twitter API)

To get rid of it, simply add an if statement around your http request

if (req.url != '/favicon.ico') {
// send your request
}

Also found a useful snippet in gist on this: https://gist.github.com/763822

Working with http requests in node.js (similar to curl)

Today I wanted to test out how to fetch data from one of the http APIs and save it to Mongo.

A quick example: get Twitter profile data for a given Twitter username.

In languages like PHP, we’d call curl and pass the URL. With node.js it’s actually really simple, we just call the GET method.

We are setting our request object that will call “GET” with our specified URL and wait to receive the response.

Request also has another method “on” that will listen for response data to come back (‘data’ event).

NOTE: It is not enough to just detect the ‘response’ event, as it looks like data coming back in “chunks”. I created a variable called “completeResponse” that concatenated all chunks into the final complete response (before I added that, my app would throw errors because of incomplete json that I tried running through JSON.parse()). Then wait for the ‘end’ event before actually saving the data into mongo.

Detailed info on http request and this issue

After you get your final parsed data object, it’s ready to be saved into mongo.

Working example can be found on github: https://github.com/ntanya/datacoll.git

(right now it’s all running on local machine)

Super simple file upload with node.js

Here’s a quick and dirty tutorial on how to upload files with node. I didn’t use any dependencies aside from “fs” that allows us to move the file from the temp location to where we need it to be. We’ll also use express to make it super easy.

First, add all required modules and create our server:

Now let’s render a page with a form:

And add a post method to handle uploads once the form is submitted.

First, check out log to see what you’re getting in res.files:

app.post('/', function(req, res){
console.log(JSON.stringify(req.files)); // this will let you see what you're getting in the files

});

And to complete this, we’ll actually need to save the uploaded file into our desired location, in my case it’s /public/images folder:

Note: in res.files object, make sure that your file name is the same name as the input field.
<input type="file" name="uploadfile" />
var temp_path = req.files.uploadfile.path;

Thanks to hacksparrow for the post on this.

Complete working example on github

Staying current in technology

My favorite tech person and mentor of all times is Mike. And when I’m not having enlightened discussions with him over lunch or in the office, I’m on his blog reading stuff that he somehow manages to churn every day (jealous of his mad writing skillz :)

Today, he writes:

In tech, we’re sort of fucked compared to say a violinist, who can be pretty sure their main tool of the trade isn’t going to change much from the day they pick it up to the day they die, so they can sink all that energy into pure, beautiful mastery. In tech, we don’t even know if our keyboards are going to look the same 5 years from now.

All us, readers of his blog know that his “violin” is a solid combo of Linux/vim/Python/Mercurial – which makes a ton of sense, and if you’re good with that stuff you are golden.

My additional thinking is that javascript, that grew from just something that your browser supports natively into de-facto standard of the coolest new technologies, from advanced client-side frameworks (prototype, jquery, and newer stuff like backbone) to databases (mongo) to server-side (node). So now, the power is in hands of javascript masters: if you know the language, you know how to build up any app, all aspects of it. I definitely has its quirks (callbacks, ubiquituos “this”), but to me they are like delicious puzzles that once solved, promise great rewards. That’s what I’m sticking to for now, and having fun with it.