Kevin Kevin - 20 days ago 5
Node.js Question

Something weird about express session store

If I store an object in session like this:

user.name = "Kelvin"; // user is an object pass by "mongoose" findOne's callback.
req.session.user = user;
console.log(req.session.user.name); // Kelvin


and after that, I access "user" in other routes of express:

app.get("/somepath", function(req, resp) {
console.log(req.session.user.name); // undefined
});


I want to know why req.session.user.name is undefined besides the function I set it?

Answer

After looking into mongoose source code I can say that this is because how mongoose models and session works. When you call req.session.user = user then req.session.user points to the object but actually the data needs to be stored somewhere (like memory or Redis).

In order to do that Express calls JSON.stringify(sess) and string is stored in memory. Here's where mongoose enters. Models are constructed in such a way, that when you stringify them only attributes predefined in Schema are included. So when you set req.session.user = user Express stringifies user (you loose name attribute) and saves the data. When you call req.session.user in another route Express parses stringified data and you obtain object without name attribute.

Now how to fix this? There are several ways.

  • Add name attribute to the Schema;
  • Define new literal object for user:

    var newuser = { id: user.id, name : "Kelvin", pwd: user.pwd, etc. }; req.session.user = newuser;

  • Store name in another field: req.session.name = "Kelvin"; (the best solution imho)

By the way: You shouldn't hold the user object in session. What if some other user like administrator makes changes to the user object? You won't see them at all. I advice holding only the id of the user in session and make custom middleware to load user from DB and store it in request object.