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}
Advertisements

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