Answer a question

I've written the following test code illustrating my problem:

var express     = require("express"),
    MongoStore  = require("connect-mongo")(express),
    mongoose    = require("mongoose"),
    config      = require(process.cwd() + "/src/config");

exports.run = function() {
    console.info("running http server");

    //create a new HTTP server
    var server = express();

    //sessions
    server.use(express.cookieParser(config.sessions.secret));
    server.use(express.session({
        secret: config.sessions.secret,
        key: config.sessions.key,
        proxy: true,
        cookie: {maxAge: config.sessions.maxAge, signed: true},
        store: new MongoStore({
            mongoose_connection: mongoose.connection
        }, onStoreSetup)}));

    //create a test ObjectID parameter
    var testObjId = new mongoose.Types.ObjectId("522bb0205a259c636c000006");
    server.get("/", function(req, res) {
        if (req.session && req.session.testObjId) {
            res.send("req.session.testObjId now has type " + typeof req.session.testObjId + " - WHY A STRING?");
        }
        else {
            req.session.testObjId = testObjId;
            req.session.save(function(err) {
                if (err) throw err;
                res.send("req.session.testObjId has type " + typeof req.session.testObjId + " - an Object, as expected - NOW REFRESH THIS PAGE");
            });
        }
    });

    //listen for incoming connections once session store is setup
    function onStoreSetup() {
        console.info("mongo session store connected");

        server.listen(config.http.port);
        console.info("http server listening on port %d", config.http.port);
    }
};

First it writes a variable with type ObjectId (from MongoDB native) to the server side session store. When you then refresh the page, the session is used, and the type of the parameter has suddenly changed to a string.

In short, if you run the above code the following will display:

  1. visit /

    Response: req.session.testObjId has type object - NOW REFRESH THIS PAGE

  2. visit / again

    Response: req.session.testObjId now has type string - WHY A STRING?

Why did it transform to a string?

Answers

MongoStore converts the session data to JSON by default based on the "stringify" option. Here's a link to the relevant source code. JSON only supports basic JavaScript data types (String, Number, boolean, etc), not custom object types such as ObjectId. To change this, pass stringify: false in your options when instantiating your MongoStore.

Update for follow-ups in comments

is there any downside to setting stringify: false?

So keep in mind that JSON supports a rich enough set of data types for most applications. The up side of JSON is it keeps your code portable to other session storage options, whereas relying on a full ObjectId instance vs a string will couple your code to mongodb without much benefit.

  • JSON
    • portable
    • neither JSON nor MongoDB are going to give you domain objects anyway, so KISS
    • ObjectId strings work correctly with == and ===. ObjectId instances need special handling to avoid the terrible instance1 === instance2 evaluating to false trap even when they represent the same underlying value.
  • MongoDB document
    • get real dates
    • ObjectId instances (which I think are actually less useful than strings, by the way)
    • Probably better querying options

So either approach is viable and there are trade-offs. I would just use the default behavior unless/until you have a strong need for stringify:false.

I think Mongo is capable of storing any object?

Well, let's be precise here. There are pure data objects made from javascript scalar data types, and then there are functions and methods and objects with behavior. A mongodb ObjectId isn't just pure data. It represents a binary value which can be stored as a hex string or a binary number, but it wraps it in an instance with specific methods and functions associated with it. JavaScript supports a set of types, JSON is a subset of that (no functions, other restrictions, etc), and mongodb has another set which is similar to JSON but not identical.

Logo

MongoDB社区为您提供最前沿的新闻资讯和知识内容

更多推荐