2

I'm having trouble getting data from MongoDB using mongoose schemas with express. I first tested with just mongoose in a single file (mongoosetest.js) and it works fine. But when I start dividing it all up with express routes and config files, things start to break. I'm sure it's something simple, but I've spent the last 3 hours googling and trying to figure out what I'm doing wrong and can't find anything that matches my process enough to compare.

mongoosetest.js (this works fine, but not for my application)

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/meanstack');

var db = mongoose.connection;

var userSchema = mongoose.Schema({
  name: String
}, {collection: 'users'});

var User = mongoose.model('User', userSchema);

User.find(function(err, users) {
  console.log(users);
});

These files are where I'm having issues. I'm sure it's something silly, probably a direct result of using external files, exports, and requires. My server.js file just starts up and configures express. I also have a routing file and a db config file.

routing file (allRoutes.js)

var express = require('express');
var router = express.Router();
var db = require('../config/db');
var User = db.User();

// routes
router.get('/user/list', function(req, res) {
  User.find(function(err, users) {
    console.log(users);
  });
});

// catch-all route
router.get('*', function(req, res) {
  res.sendfile('./public/index.html');
});

module.exports = router;

dbconfig file (db.js)

var mongoose = require('mongoose');
var dbHost = 'localhost';
var dbName = 'meanstack';
var db = mongoose.createConnection(dbHost, dbName);
var Schema = mongoose.Schema, ObjectId = Schema.ObjectId;

db.once('open', function callback() {
  console.log('connected');
});

// schemas
var User = new Schema({
  name    : String
}, {collection: 'users'});

// models
mongoose.model('User', User);
var User = mongoose.model('User');

//exports
module.exports.User = User;

I receive the following error when I browse to localhost:3000/user/list

TypeError: Object { _id: 5398bed35473f98c494168a3 } has no method 'find' at 
Object.module.exports [as handle] (C:\...\routes\allRoutes.js:8:8) at next_layer 
(C:\...\node_modules\express\lib\router\route.js:103:13) at Route.dispatch 
(C:\...\node_modules\express\lib\router\route.js:107:5) at 
C:\...\node_modules\express\lib\router\index.js:213:24 at Function.proto.process_params 
(C:\...\node_modules\express\lib\router\index.js:284:12) at next 
(C:\...\node_modules\express\lib\router\index.js:207:19) at Function.proto.handle 
(C:\...\node_modules\express\lib\router\index.js:154:3) at Layer.router 
(C:\...\node_modules\express\lib\router\index.js:24:12) at trim_prefix 
(C:\...\node_modules\express\lib\router\index.js:255:15) at 
C:\...\node_modules\express\lib\router\index.js:216:9

Like I said, it's probably something silly that I'm messing up with trying to organize my code since my single file (mongoosetest.js) works as expected. Thanks.

sdouble
  • 1,055
  • 3
  • 11
  • 28

2 Answers2

2

Why are you calling User?

var User = db.User();

Try

var User = db.User;

Calling it is allowed, since it is a constructor, but it probably doesn't return anything useful (the error message implies that it is constructing an empty User object, I think).

Aaron Dufour
  • 17,288
  • 1
  • 47
  • 69
  • var User = db.User; results in a long hang and timeout. db.User(); results in an instant error. – sdouble Jun 11 '14 at 21:21
  • @sdouble But is it `console.log`ing during the "long hang"? You're never sending a response, so the hanging is expected behavior. – Aaron Dufour Jun 11 '14 at 21:43
  • No, there's nothing. I have also added another console.log('test') right before the c.log(users) and that doesn't echo out either. Once it hits .find, it's toast. I have no problem at all if I do it all in a single file, so I think it's something to do with how I'm referencing. – sdouble Jun 12 '14 at 02:27
1

I figured it out.

Apparently, db.once('open'... isn't the same as mongoose.connect. Switched my dbconfig.js file to the following and all is well (using var User = db.User; in allRoutes.js as Aaron Dufour suggested).

var mongoose = require('mongoose');
var Schema = mongoose.Schema, ObjectId = Schema.ObjectId;

mongoose.connect('mongodb://localhost/meanstack');

// schemas
var User = new Schema({
  name    : String
}, {collection: 'users'});

// models
mongoose.model('User', User);

//exports
module.exports.User = mongoose.model('User');

EDIT: Can't mark this as the answer for 2 days.

sdouble
  • 1,055
  • 3
  • 11
  • 28
  • 1
    It's not so much `db.once` vs `mongoose.connect`, but `mongoose.createConnection` vs `mongoose.connect`. You should really only need to use `mongoose.createConnection` if you need multiple connections open. When you use `mongoose.createConnection` it will create multiple, and you have to specify which you use in the query calls. Because you weren't specifying which one to use, the query hung. Switching to `mongoose.connect` has only one connection, so the query succeeds. – dylants Jun 12 '14 at 03:50
  • For more information on this see http://mongoosejs.com/docs/connections.html (or this stack overflow answer is useful as well: http://stackoverflow.com/a/22838614) – dylants Jun 12 '14 at 03:51
  • @dylants thanks, that helped me quite a bit. I changed my original code to db.model instead of mongoose.model and it worked as well. It makes a lot more sense to me now. mongoose.connection opens a default connection for mongoose, but mongoose.createConnection opens and returns a connection. What I seem to have been doing is creating/opening a new connection but trying to work off of the default connection that I never connected. – sdouble Jun 12 '14 at 13:24
  • Right, exactly :) I don't know why mongoose doesn't use the default connection (connections[0]) when you call createConnection if it hasn't been established/created yet. They seem to instead expect you to use `connect` first and then `createConnection` for additional connections. – dylants Jun 12 '14 at 14:25