12

I have defined a Model with mongoose like this:

var mongoose = require("mongoose")
var Schema = mongoose.Schema

var userObject = Object.create({
    alias: String,
    email: String,
    password: String,
    updated: { 
        type: Date,
        default: Date.now
    }
})

var userSchema = new Schema(userObject, {strict: false})
var User = mongoose.model('User', userSchema)

module.exports = User

Then I created a user that I can perfectly find through mongo console like this:

db.users.findOne({ email: "coco@coco.com" });
{
    "_id" : ObjectId("55e97420d82ebdea3497afc7"),
    "password" : "caff3a46ebe640e5b4175a26f11105bf7e18be76",
    "gravatar" : "a4bfba4352aeadf620acb1468337fa49",
    "email" : "coco@coco.com",
    "alias" : "coco",
    "updated" : ISODate("2015-09-04T10:36:16.059Z"),
    "apps" : [ ],
    "__v" : 0
}

However, when I try to access this object through a node.js with mongoose, the object a retrieve is not such doc, but a wrapper:

This piece of code...

// Find the user for which the login queries
  var User = require('../models/User')
  User.findOne({ email: mail }, function(err, doc) {
    if (err) throw err
      if (doc) {
        console.dir(doc)
        if(doc.password == pass) // Passwords won't match

Produces this output from console.dir(doc)...

{ '$__': 
   { strictMode: false,
     selected: undefined,
     shardval: undefined,
     saveError: undefined,
     validationError: undefined,
     adhocPaths: undefined,
     removing: undefined,
     inserting: undefined,
     version: undefined,
     getters: {},
     _id: undefined,
     populate: undefined,
     populated: undefined,
     wasPopulated: false,
     scope: undefined,
     activePaths: { paths: [Object], states: [Object], stateNames: [Object] },
     ownerDocument: undefined,
     fullPath: undefined,
     emitter: { domain: null, _events: {}, _maxListeners: 0 } },
  isNew: false,
  errors: undefined,
  _doc: 
   { __v: 0,
     apps: [],
     updated: Fri Sep 04 2015 12:36:16 GMT+0200 (CEST),
     alias: 'coco',
     email: 'coco@coco.com',
     gravatar: 'a4bfba4352aeadf620acb1468337fa49',
     password: 'caff3a46ebe640e5b4175a26f11105bf7e18be76',
     _id: { _bsontype: 'ObjectID', id: 'Uét Ø.½ê4¯Ç' } },
  '$__original_validate': { [Function] numAsyncPres: 0 },
  validate: [Function: wrappedPointCut],
  _pres: { '$__original_validate': [ [Object] ] },
  _posts: { '$__original_validate': [] } }

Therefore, passwords won't match because doc.password is undefined.

Why is this caused?

jsdario
  • 6,477
  • 7
  • 41
  • 75
  • 1
    Use `console.log`, not `console.dir` to sanely log Mongoose model instances. – JohnnyHK Sep 04 '15 at 13:04
  • Yeah, as a fact `console.log(doc)` only printed the wrapped document, but the password validation still did not work and `doc.password` still returned `undefined` without `console.dir(doc)`. – jsdario Sep 04 '15 at 13:49

1 Answers1

15

That's exactly the purpose of mongoose, wrapping mongo objects. It's what provides the ability to call mongoose methods on your documents. If you'd like the simple object, you can call .toObject() or use a lean query if you don't plan on using any mongoose magic on it at all. That being said, the equality check should still hold as doc.password returns doc._doc.password.

chrisbajorin
  • 5,993
  • 3
  • 21
  • 34
  • 2
    Great. It worked! Thank you really. Do you know why in several tutorials and snippets –like [this one in mongoose docs](http://mongoosejs.com/docs/queries.html)– the method `.toObject()` is not used? – jsdario Sep 04 '15 at 13:44
  • It's not a necessity. If you're using mongoose, chances are, you want the mongoose document. – chrisbajorin Sep 04 '15 at 13:46
  • 1
    Sorry to be so insisting I want to fully understand; In the [linked example](http://mongoosejs.com/docs/queries.html) mongoose object is used to access **directly** to document params (like `person.occupation`). In my case that did not work, since `doc.password` always returns `undefined` unless I apply `.toObject()` first. – jsdario Sep 04 '15 at 13:56
  • 1
    Try this: `doc.password === doc._doc.password`. That should evaluate to true. In the example you linked, when you access `person.occupation` it returns `person._doc.occupation`. This is why I don't understand your error. If `doc.toObject().password` makes your code work, `doc.password` should work as well. – chrisbajorin Sep 04 '15 at 14:19
  • Thank you soo much!! This bit just helped me fix an issue that had me stuck for hours. I was trying to modify my server side rendered React app config thinking that this was a react context issue but turns out it was MongoDB. – larrydalmeida Nov 11 '17 at 18:43