3

Im using this scheme for a session in my node.js app

var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;
// define the schema for our user session model
var UserSessionSchema   = new Schema({
    sessionActivity:    { type: Date, expires: '15s' }, // Expire after 15 s
    user_token:         { type: String, required: true }
});
module.exports = mongoose.model('UserSession', UserSessionSchema);

And I create a "session" in my app with:

...
var session = new Session();
session.user_token = profile.token;
session.save(function(save_err) {
    if (save_err) {
        ....
    } else {
        // store session id in profile
        profile.session_key = session._id;
        profile.save(function(save_err, profile) {
            if (save_err) {
                ...
            } else {
                res.json({ status: 'OK', session_id: profile.session_id });
            }
});
...

The problem is that the document lives permanetly, its never expires. It should only live for 15 seconds (up to a minute). Whats wrong with my code? I have tried to set the expries: string to a number i.e 15, to a string '15s' and so on.

Goran
  • 1,002
  • 3
  • 14
  • 29
  • possible duplicate of [Setting expiry time for a collection in mongodb using mongoose](http://stackoverflow.com/questions/14597241/setting-expiry-time-for-a-collection-in-mongodb-using-mongoose) – Christian P Jun 03 '14 at 07:06
  • 1
    TTL indexes require a integer for seconds till expiry and not a string. The process is also run every minute. So that can take up to one minute from expiry time. – Neil Lunn Jun 03 '14 at 07:07
  • I have tried with setting the expires property with a number. I have read that question Christian, but I dont really get the note: "It's up to you to set createdAt to the current time when creating docs." Do I need to set createdAt to Date.now() or something like that? – Goran Jun 03 '14 at 07:24

2 Answers2

9
var UserSessionSchema   = new Schema({
    sessionActivity:    { type: Date, expires: '15s', default: Date.now }, // Expire after 15 s
    user_token:         { type: String, required: true }
});

A TTL index deletes a document 'x' seconds after its value (which should be a Date or an array of Dates) has passed. The TTL is checked every minute, so it may live a little longer than your given 15 seconds.

To give the date a default value, you can use the default option in Mongoose. It accepts a function. In this case, Date() returns the current timestamp. This will set the date to the current time once.

You could also go this route:

UserSessionSchema.pre("save", function(next) { 
    this.sessionActivity = new Date(); 
    next(); 
});

This will update the value every time you call .save() (but not .update()).

RickN
  • 12,537
  • 4
  • 24
  • 28
  • Thank you, but I cant this to work, The documents get deleted after a long time, but not in 15secs (or in about a minute). If I run ISODate() to get the local time in the shell i get "ISODate("2014-06-03T09:55:35.473Z")" but the document still exists. If I check the document I can see that "sessionActivity" has the value ISODate("2014-06-03T09:49:57.977Z"). It should have been deleted several minutes ago. – Goran Jun 03 '14 at 09:56
  • What's the output of `db.usersessions.getIndexes()` in the mongo shell? (You might need to correct the collection name). There should be an entry like `{"key": {"sessionActivity": 1} "expireAfterSeconds": }` – RickN Jun 03 '14 at 11:02
  • > db.usersessions.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "aquamoto.usersessions" }, { "v" : 1, "key" : { "sessionActivity" : 1 }, "name" : "sessionActivity_1", "ns" : "aquamoto.usersessions", "expireAfterSeconds" : 15, "background" : true } ] > – Goran Jun 03 '14 at 11:19
  • Now it works! { type: Date, expires: '15s', default: Date } didnt work, but UserSessionSchema.pre("save", function(next) { this.sessionActivity = new Date(); next(); }); with { type: Date, expires: 15 } works!!! Dont know why but it works :) – Goran Jun 03 '14 at 11:21
  • `default: Date` works fine for me, but it seems that most examples advocate `default: Date.now`. The first (`Date()`) will return a string which is then cast to a `Date` object, the second (`Date.now()`) a UNIX timestamp which is cast to a `Date` object in a more fool-proof way. Perhaps locale settings interfere in some way in the first form. I've updated my answer to reflect this. – RickN Jun 03 '14 at 12:43
  • You missed the ( ) after Date.now( ) in your answer. – kungfuspider Apr 07 '15 at 23:33
  • 2
    Actually, I didn't. The value `Date.now` is a function, which means that Mongoose will run that function every time it needs a default value. If you were to add brackets, (`default: Date.now()}`), then the value would be evaluated once and it would always be the same date (more specifically: the time when you started your script). – RickN Apr 08 '15 at 09:15
0

To double check the indexes that have been created in the DB you can run this command in your mongo shell db.yourdb.getIndexes(). When changing the indexes you have to manually delete it in the collection before the new one will take effect. Check here for more information Mongoose expires property not working properly

Community
  • 1
  • 1
Luke Kroon
  • 1,016
  • 12
  • 19