Mongoose: FindOne returns default value of the nonexistent filed.

Created on 23 Jul 2016  路  3Comments  路  Source: Automattic/mongoose

_First: A workaround to overcome this issue:_
Model.findOne({id: 'blabla'}).select('email password createdAt').lean().exec()

issue:

I use an createdAt field -which has an expires (TTL 24h) and a default (Date.now) value- in my Users model to store the creating date info of the new created users.

If the user activates the account the system removes the createdAt field.
If the user doesn't activate the account the system remove the account from Users collection after 24 hours.

In my authentication operations, I check the existing of createdAt field firstly.
If the user is not activated I show a message like Account is not activated.

When I try FindOne method for purpose of the above authentication procedure, I get Date.now value although there is no a createdAt field in the document because of the user has activated his account.

createdAt field in my User model:
createdAt: { type: Date, expires: '24h', default: Date.now },

My method:
Users.findOne({email: username}, 'email, password, createdAt', function(err, user) {

By using the above method createdAt value returns at every time.

ps: i searched the issue but i couldn't anything.

Most helpful comment

Stumbled upon the same problem.
@vkarpov15 it should not work that way. Although default value is set on saving it is misleading to set it when find the document, because it should actually return exact data stored in DB, isn't it? I would vote for reopening the issue.

All 3 comments

That's just how defaults work, when there isn't a createdAt field in the doc mongoose will add one. If you only want to add createdAt when creating a new doc:

schema.pre('save', function(next) {
  if (this.isNew) {
    this.createdAt = Date.now();
  }
  next();
});

Also, I wouldn't recommend separating the fields in your projection Users.findOne({email: username}, 'email, password, createdAt' /** <-- remove commas here */) with commas.

Stumbled upon the same problem.
@vkarpov15 it should not work that way. Although default value is set on saving it is misleading to set it when find the document, because it should actually return exact data stored in DB, isn't it? I would vote for reopening the issue.

Not necessarily, mongoose has a lot of places where the document doesn't represent the exact data stored in the db: getters, virtuals, etc. Either way, we assert on this behavior and changing it would break a lot of people's code, so we won't change it unless there's a lot of demand to change it. Here's a workaround:

createdAt: {
  type: Date,
  default: function() {
    if (this.isNew) { return new Date(); }
    return undefined;
  }
}

This will make it so that createdAt is only set when saving to the database, but it'll be undefined if you loaded a doc from the db and createdAt isn't set.

Was this page helpful?
0 / 5 - 0 ratings