mongoose statics `this` is not a model reference

Created on 27 Sep 2016  路  7Comments  路  Source: Automattic/mongoose

I am using mongoose v4.5.3

I am having trouble with mongoose statics function. this keyword inside a static function should refer to the model (so that we can use .find and other query) but in my case this is completely different. Hence this.find is showing undefined.

this is below

{ DTRACE_NET_SERVER_CONNECTION: [Function],
  DTRACE_NET_STREAM_END: [Function],
  DTRACE_HTTP_SERVER_REQUEST: [Function],
  DTRACE_HTTP_SERVER_RESPONSE: [Function],
  DTRACE_HTTP_CLIENT_REQUEST: [Function],
  DTRACE_HTTP_CLIENT_RESPONSE: [Function],
  COUNTER_NET_SERVER_CONNECTION: [Function],
  COUNTER_NET_SERVER_CONNECTION_CLOSE: [Function],
  COUNTER_HTTP_SERVER_REQUEST: [Function],
  COUNTER_HTTP_SERVER_RESPONSE: [Function],
  COUNTER_HTTP_CLIENT_REQUEST: [Function],
  COUNTER_HTTP_CLIENT_RESPONSE: [Function],
  global: [Circular],
  process:
   process {
     title: 'Console2 command window - node  server.js',
     version: 'v4.4.7',
     moduleLoadList:
      [ 'Binding contextify',
        'Binding natives',
        'NativeModule events',
        'NativeModule buffer',
        'Binding buffer',
        'NativeModule internal/util',
        'Binding util',
        'NativeModule timers',
        'Binding timer_wrap',
        'NativeModule _linklist',
        'NativeModule assert',
        'NativeModule util',
        'Binding uv',
        'NativeModule path',
        'NativeModule module',
        'NativeModule internal/module',
        'NativeModule vm',
        'NativeModule fs',
        'Binding fs',
        'NativeModule constants',
        'Binding constants',
        'NativeModule stream',
        'NativeModule _stream_readable',
        'NativeModule _stream_writable',
        'NativeModule _stream_duplex',
        'NativeModule _stream_transform',
        'NativeModule _stream_passthrough',
        'Binding fs_event_wrap',
        'NativeModule net',
        'NativeModule internal/net',
        'Binding cares_wrap',
        'Binding tty_wrap',
        'Binding tcp_wrap',
        'Binding pipe_wrap',
        'Binding stream_wrap',
        'NativeModule tls',
        'NativeModule url',
        'NativeModule punycode',
        'NativeModule querystring',
        'Binding crypto',
        'NativeModule _tls_common',
        'NativeModule _tls_wrap',
        'NativeModule crypto',
        'NativeModule internal/streams/lazy_transform',
        'NativeModule string_decoder',
        'NativeModule _stream_wrap',
        'Binding js_stream',
        'Binding tls_wrap',
        'NativeModule _tls_legacy',
        'NativeModule os',
        'Binding os',
        'NativeModule dns',
        'NativeModule tty',
        'Binding signal_wrap',
        'NativeModule console',
        'NativeModule http',
        'NativeModule _http_incoming',
        'NativeModule _http_common',
        'NativeModule internal/freelist',
        'Binding http_parser',
        'NativeModule _http_outgoing',
        'NativeModule _http_server',
        'NativeModule _http_agent',
        'NativeModule _http_client',
        'NativeModule zlib',
        'Binding zlib',
        'NativeModule cluster',
        'NativeModule dgram',
        'Binding udp_wrap',
        'NativeModule child_process',
        'Binding spawn_sync',
        'NativeModule internal/child_process',
        'Binding process_wrap',
        'NativeModule internal/socket_list',
        'NativeModule internal/cluster' ],
     versions:
      { http_parser: '2.5.2',
        node: '4.4.7',
        v8: '4.5.103.36',
        uv: '1.8.0',
        zlib: '1.2.8',
        ares: '1.10.1-DEV',
        icu: '56.1',
        modules: '46',
        openssl: '1.0.2h' },
     arch: 'x64',
     platform: 'win32',
     release:
      { name: 'node',
        lts: 'Argon',
        sourceUrl: 'https://nodejs.org/download/release/v4.4.7/node-v4.4.7.tar.gz',
        headersUrl: 'https://nodejs.org/download/release/v4.4.7/node-v4.4.7-headers.tar.gz',
        libUrl: 'https://nodejs.org/download/release/v4.4.7/win-x64/node.lib' },
     argv:
      [ 'C:\\Program Files\\nodejs\\node.exe',
        'C:\\var\\Public Gits\\freespeech\\server.js' ],
     execArgv: [],
     env:
      { ALLUSERSPROFILE: 'C:\\ProgramData',
        APPDATA: 'C:\\Users\\FrameInn\\AppData\\Roaming',
        'asl.log': 'Destination=file',
        ChocolateyInstall: 'C:\\ProgramData\\chocolatey',
        ChocolateyLastPathUpdate: 'Sat Jul  2 10:45:02 2016',
        CommonProgramFiles: 'C:\\Program Files\\Common Files',
        'CommonProgramFiles(x86)': 'C:\\Program Files (x86)\\Common Files',
        CommonProgramW6432: 'C:\\Program Files\\Common Files',
        COMPUTERNAME: 'FRAMEINNUDAY',
        ComSpec: 'C:\\Windows\\system32\\cmd.exe',
        easyplussdk: '"C:\\Program Files (x86)\\Common Files\\lenovo\\easyplussdk\\bin"',
        FP_NO_HOST_CHECK: 'NO',
        HOMEDRIVE: 'C:',
        HOMEPATH: '\\Users\\FrameInn',
        JAVA_HOME: 'C:\\Program Files\\Java\\jdk1.8.0_101',
        LOCALAPPDATA: 'C:\\Users\\FrameInn\\AppData\\Local',
        LOGONSERVER: '\\\\FRAMEINNUDAY',
        MAGICK_HOME: 'C:\\imagick\\modules\\coders',
        NUMBER_OF_PROCESSORS: '4',
        OPENSSL_CONF: 'C:\\OpenSSL\\bin\\openssl.cfg',
        OS: 'Windows_NT',
        Path: 'C:\\ProgramData\\Oracle\\Java\\javapath;c:\\program files\\graphicsmagick-1.3.24-q16;C:\\php;C:\\imagick;C:\\Program Files (x86)\\Intel\\iCLS Client\\;C:\\Program Files\\Intel\\iCLS Client\\;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\DAL;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\DAL;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\IPT;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\IPT;C:\\Program Files\\Intel\\WiFi\\bin\\;C:\\Program Files\\Common Files\\Intel\\WirelessCommon\\;C:\\php;C:\\imagick;C:\\Program Files (x86)\\Common Files\\lenovo\\easyplussdk\\bin;C:\\Program Files (x86)\\GnuWin32\\bin;C:\\Python27;C:\\Apache24\\bin;C:\\mongodb\\bin;C:\\nginx-1.10.0;C:\\Program Files\\nodejs\\;C:\\ProgramData\\chocolatey\\bin;C:\\Program Files (x86)\\Windows Kits\\8.1\\Windows Performance Toolkit\\;C:\\Windows\\system32\\config\\systemprofile\\.dnx\\bin;C:\\Program Files\\Microsoft DNX\\Dnvm\\;C:\\Program Files\\Git\\cmd;C:\\Program Files (x86)\\Dev-Cpp\\MinGW64\\bin;C:\\Users\\FrameInn\\AppData\\Roaming\\npm;C:\\Users\\FrameInn\\AppData\\Local\\atom\\bin',
        PATHEXT: '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.INI;.PY',
        PROCESSOR_ARCHITECTURE: 'AMD64',
        PROCESSOR_IDENTIFIER: 'Intel64 Family 6 Model 61 Stepping 4, GenuineIntel',
        PROCESSOR_LEVEL: '6',
        PROCESSOR_REVISION: '3d04',
        ProgramData: 'C:\\ProgramData',
        ProgramFiles: 'C:\\Program Files',
        'ProgramFiles(x86)': 'C:\\Program Files (x86)',
        ProgramW6432: 'C:\\Program Files',
        PROMPT: '$P$G',
        PSModulePath: 'C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules\\',
        PUBLIC: 'C:\\Users\\Public',
        PYTHON: 'C:\\Python27\\python.exe',
        PYTHONPATH: 'C:\\Python27',
        SESSIONNAME: 'Console',
        SystemDrive: 'C:',
        SystemRoot: 'C:\\Windows',
        TEMP: 'C:\\Users\\FrameInn\\AppData\\Local\\Temp',
        TMP: 'C:\\Users\\FrameInn\\AppData\\Local\\Temp',
        UOIPME_REG_PATH: 'C:\\Program Files\\Intel Corporation\\USB over IP',
        USERDOMAIN: 'FRAMEINNUDAY',
        USERDOMAIN_ROAMINGPROFILE: 'FRAMEINNUDAY',
        USERNAME: 'FrameInn',
        USERPROFILE: 'C:\\Users\\FrameInn',
        VS140COMNTOOLS: 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\',
        windir: 'C:\\Windows' },
     pid: 9772,
     features:
      { debug: false,
        uv: true,
        ipv6: true,
        tls_npn: true,
        tls_sni: true,
        tls_ocsp: true,
        tls: true },
     _needImmediateCallback: false,
     execPath: 'C:\\Program Files\\nodejs\\node.exe',
     debugPort: 5858,
     _startProfilerIdleNotifier: [Function: _startProfilerIdleNotifier],
     _stopProfilerIdleNotifier: [Function: _stopProfilerIdleNotifier],
     _getActiveRequests: [Function: _getActiveRequests],
     _getActiveHandles: [Function: _getActiveHandles],
     reallyExit: [Function: reallyExit],
     abort: [Function: abort],
     chdir: [Function: chdir],
     cwd: [Function: cwd],
     umask: [Function: umask],
     _kill: [Function: _kill],
     _debugProcess: [Function: _debugProcess],
     _debugPause: [Function: _debugPause],
     _debugEnd: [Function: _debugEnd],
     hrtime: [Function: hrtime],
     dlopen: [Function: dlopen],
     uptime: [Function: uptime],
     memoryUsage: [Function: memoryUsage],
     binding: [Function: binding],
     _linkedBinding: [Function: _linkedBinding],
     _setupDomainUse: [Function: _setupDomainUse],
     _events:
      { newListener: [Function],
        removeListener: [Function],
        SIGWINCH: [Object] },
     _rawDebug: [Function],
     _eventsCount: 3,
     domain: null,
     _maxListeners: undefined,
     EventEmitter:
      { [Function: EventEmitter]
        EventEmitter: [Circular],
        usingDomains: false,
        defaultMaxListeners: 10,
        init: [Function],
        listenerCount: [Function] },
     _fatalException: [Function],
     _exiting: false,
     assert: [Function],
     config: { target_defaults: [Object], variables: [Object] },
     nextTick: [Function: nextTick],
     _tickCallback: [Function: _tickCallback],
     _tickDomainCallback: [Function: _tickDomainCallback],
     stdout: [Getter],
     stderr: [Getter],
     stdin: [Getter],
     openStdin: [Function],
     exit: [Function],
     kill: [Function],
     mainModule:
      Module {
        id: '.',
        exports: {},
        parent: null,
        filename: 'C:\\var\\Public Gits\\freespeech\\server.js',
        loaded: true,
        children: [Object],
        paths: [Object] },
     _immediateCallback: [Function: processImmediate] },
  GLOBAL: [Circular],
  root: [Circular],
  Buffer:
   { [Function: Buffer]
     poolSize: 8192,
     isBuffer: [Function: isBuffer],
     compare: [Function: compare],
     isEncoding: [Function],
     concat: [Function],
     byteLength: [Function: byteLength] },
  clearImmediate: [Function],
  clearInterval: [Function],
  clearTimeout: [Function],
  setImmediate: [Function],
  setInterval: [Function],
  setTimeout: [Function],
  console: [Getter],
  addresses: { ipv6: 'fe80::5efe:c0a8:64', mac: '00:00:00:00:00:00' } }

and error is

TypeError: model.findOne is not a function

static function is

authorSchema.statics.authenticate = function(req, res, next){
    var model = this;
    console.log(this);
    var authToken = req.get('x-auth-token');

    if(!authToken){
        return res.sendStatus(401);
    }

    model
    .findOne({authToken : authToken}, function(err, doc){
        if(err)             return res.sendStatus(500);
        if(_.isEmpty(doc))  return res.sendStatus(403);
                            return next();
    });

}

I am using it as a express middleware

Models = require(_dir + '/_mongoose/Models')
Router.put('/', Models.Author.authenticate, function(req, res){
    res.send("You are allowed!");
});
won't fix

Most helpful comment

I wouldn't recommend using mongoose functions as express middleware directly, trying to get 2 different abstractions to play nicely together is pretty difficult, I'd recommend just doing something like:

Router.put('/', function(req, res, next) { Models.Author.authenticate.then(next, next); }, function(req, res){
    res.send("You are allowed!");
});

All 7 comments

Huh, looks like express calls it's middlewares with this of a http server instance. In that case, I have bind static function with it's model like

Router.put('/', Models.Author.authenticate.bind(Models.Author), function(req, res){
    res.send("You are allowed!");
});

then it works. But I don't know if it will effect any other functionalities. Let me know.

I wouldn't recommend using mongoose functions as express middleware directly, trying to get 2 different abstractions to play nicely together is pretty difficult, I'd recommend just doing something like:

Router.put('/', function(req, res, next) { Models.Author.authenticate.then(next, next); }, function(req, res){
    res.send("You are allowed!");
});

Why not to bind static methods to models anyway? they will be more intuitive to use, aren't they?

@cyper8 good idea, I'll re-open this and consider it for a future release

I don't like the idea of binding static methods to the Model. It allows us to do neat things with inheritance. For example, let's say I define a field in a superclass called foo that was determined to be private. Good programming practices dictate that subclasses therefore shouldn't know about this field, but I still want to find instances of the subclass using foo. All I have to do is something like

Subclass.statics.findByFoo = function findByFoo(bar) {
  Superclass.findByFoo.apply(this, arguments);
};

It also works for static methods I have come to call "pseudo-constructors". These methods allow me to hide away some of the private information of some of my schemas. Subclasses of the original schema can call the parent class (schema)'s pseudo-constructor just like it would normally. For example,

User.createUser = function createUser(name, username, password) {
  names = name.split(' ');

  return new this({
    firstName: names[0]
    lastName:  names[names.length - 1],
    username:  username,
    password:  password
  });
};

// Later, a "subschema"'s pseudo-constructor might look like this:
Customer.createCustomer = function createCustomer(name, username, password, customerId) {
  const customer = User.createUser.call(this, name, username, password);

  customer.customerId = customerId;
};

These pseudo-constructors and static methods that define top-level queries are where I see the advantages of bindable static methods and these are widely used in my code base.

Sounds like a valid use case, I'll revert these changes. Hadn't thought of this case. Guess users that want to use statics as express middleware will just have to do .bind() on their own :)

Models = require(_dir + '/_mongoose/Models')
Router.put('/', Models.Author.authenticate.bind(Models.Author), function(req, res){
    res.send("You are allowed!");
});
Was this page helpful?
0 / 5 - 0 ratings