I am trying to run a simple mongoose/node example which I found here on stackoverflow:
var mongoose = require('mongoose'),
db = mongoose.connect('mongodb://localhost/db'),
Schema = mongoose.Schema;
var sentinel = setTimeout(function(){
throw "failed to connect to MongoDB after one minute!";
}, 60*1000); // 60 seconds
mongoose.model('User', new Schema({
properties: {
name : { type: String, index: true }
}
}));
var User = db.model('User');
var u = new User();
u.name = 'Foo';
u.save();
User.find().all(function(arr) {
clearTimeout(sentinel); // cancel the timeout sentinel
console.log('Users found');
console.log(arr);
console.log('length='+arr.length);
});
process.stdin.resume();
If I get the code right there should be an output in the terminal at the end of the script, where the message "Users found" and all users from the collection should be printed. But I just get the timeout message. Why that?
I am running my server on an Amazon EC2 micro instance. Node, Mongodb and mongoose are installed and a Mongodb server is running (I can interact with it from the terminal via "mongo"). I have also created the directory /data/db.
I don't know about mongoose but u.save() might be asynchronous because it writes to the DB. Try
u.save(function (err){
if(err) console.log(err);
User.find().all(function(arr) {
clearTimeout(sentinel); // cancel the timeout sentinel
console.log('Users found');
console.log(arr);
console.log('length='+arr.length);
});
});
Edit: This works fine
var mongoose = require('mongoose');
var connection = mongoose.connect('mongodb://localhost/my_database');
var Schema = mongoose.Schema
var User = new Schema({
author : String
, type : String
});
var MyUserModel = mongoose.model('User', User); //create and access the model User
var u = new MyUserModel();
u.author = 'authorname';
u.save(function(err){
if (err) console.log(err);
});
MyUserModel.find({}, function (err,docs) {
console.log(docs);
});
I handled this problem by adding one additional step in each router where I use DB.
It's a little bit messy but it works and 100% no leaks.
Something like this:
// file: 'routes/api/v0/users.js'
router
var User = require('../../../models/user').User,
rest = require('../../../controllers/api/v0/rest')(User),
checkDB = require('../../../middleware/checkDB');
module.exports = function (app) {
app.get('/api/v0/users', checkDB, rest.get);
app.get('/api/v0/users/:id', checkDB, rest.getById);
app.post('/api/v0/users', checkDB, rest.post);
app.delete('/api/v0/users', checkDB, rest.deleteById);
app.put('/api/v0/users', checkDB, rest.putById);
};
// file: 'middleware/checkDB.js'
var HttpError = require('../error').HttpError,
mongoose = require('../lib/mongoose');
// method which checks is DB ready for work or not
module.exports = function(req, res, next) {
if (mongoose.connection.readyState !== 1) {
return next(new HttpError(500, "DataBase disconnected"));
}
next();
};
PS If you know solution better, please let me know.
Related
I am .NET developer and learning MEAN stack, developing an API for simple post and comment app. I am using MVC pattern without view as it is API. Here is how I am trying to create my model function :
const User = module.exports = mongoose.model('User',UserSchema);
module.exports.getUsers = function(callback){
User.find()
.exec(function(err,list_users){
if(err) { callback(); }
return list_users;
});
}
And here is the controller :
exports.user_list = function(req,res,next){
User.getUsers((err,list_users) => {
if(err){ next(err);}
res.json({user_list : list_users});
})
}
I am getting an error as getUsers is not getting imported. I am trying here to separate the data access code from controller and make controller only to manage request and response as I have been doing in .NET. Any help how can I achieve this?
I would look through the documentation to get familiar with how to use mongoose.
First thing I see is that you are not defining the methods correctly according to the documentation here http://mongoosejs.com/docs/guide.html#methods.
But you do not have to define a find() function. Mongoose already has it built in.
So the next step would be how are you creating the instance of the Model in your controller.
Your model should be:
const mongoose = require('mongoose'),
UserSchema = mongoose.Schema();
const User = new UserSchema({
// define user
});
module.exports = mongoose.model('User',UserSchema);
And the controller:
const User = require('path_to_User_model');
exports.user_list = function(req,res,next){
User.find((err,result)=>{
if(err)
// log err and send response
else
// send the result ex: res.json(result);
});
}
also read through the setup on the npmjs website. https://www.npmjs.com/package/mongoose
So to create have your data functions and have your controller use that function you may try
const mongoose = require('mongoose'),
UserSchema = mongoose.Schema();
const User = new UserSchema({
// define user
});
// data functions
User.methods.getUsers = function (){
User.find((err,result)=>{
if(err)
// log err and return something
return false;
else
return result;
});
}
module.exports = mongoose.model('User',UserSchema);
then the controller
const User = require('path_to_User_model');
exports.user_list = function(req,res,next){
var users = User.getUsers();
if (!users)
res.status(500).send('error_page');
else
res.json(users);
}
Using mongoose if I try to find a document stored in the database using db.model() like mongoose docs suggests, I get no results :(
However, if I use db.collection().find() I get results.
Why is that? and what will be the best approach using the example code below?
In app.js
var mongoose = require('mongoose');
mongoose.Promise = global.Promise;
mongoose.connect(config.database.url); // database configuration
app.locals.db = mongoose.connection;
app.locals.db.on('error', function(msg){
console.log("db connection failed", msg);
});
app.locals.db.once('open', function(){
console.log("db connected successfully");
});
In routes -> person.js
var Person = require('Person');
router.post('/search', function(req, res) {
var person = new Person(req.app.locals.db);
person.getPerson(req.body.name, function(found, docs) {
if (found === false)
res.render('pageTpl', { results: 'person not found' });
else
res.render('pageTpl', { results: docs });
});
In Person.js
// schema here returns new mongoose.Schema({ fields : types })
const personSchema = require('./schemas/personSchema');
function Person(db) {
this.db = db;
}
Person.prototype.getPerson = function(term, callback) {
var Person = this.db.model('people', personSchema);
var q = Person.find({ name: /^term/ }).sort('age').limit(2);
q.exec(function(err, results) {
if (err) return callback (false, err);
// This returns [] results
console.log(results);
callback(true, results);
});
});
module.exports = Person;
The problem is with this line: var Person = this.db.model('people', personSchema);
Mongoose automagically converts model to plural so try the following: var Person = this.db.model('person', personSchema);
After some more research I figure out why I was not getting results. It all fall into the details. In Person.js I have the following line:
var q = Person.find({ name: /^term/ }).sort('age').limit(2);
If you look closely, the problem resides in here /^term/ where term in a variable but does not get translate into its value. Instead I did:
var regTerm = new RegExp("^" + term);
Now, regTerm can be used as regular expession within find.
Hope this helps someone in the future.
I'm creating a unit test to test Passport, and the first step is to create a user. Creating the user times out and the test is unable to progress.
Test (login.js):
'use strict';
var app = require('../index'),
kraken = require('kraken-js'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
should = require('chai').should(),
Q = require('q'),
agent = require('supertest'),
cookie,
pUser = {
firstName: 'pasport-test',
lastName: 'user',
userName: 'passport-user',
email: 'passport-user#here.com',
password: 'h#rdP#ssw0rd'
}
describe('#create user and log them in with passport', function () {
this.timeout(10000);
var mock;
beforeEach(function (done) {
kraken.create(app).listen(function (err, server) {
mock = server;
done(err);
});
});
afterEach(function (done) {
mock.close(done);
});
describe('#login the user', function () {
it('should create a user', function (done) {
var user = new User({
firstName: pUser.firstName,
lastName: pUser.lastName,
userName: pUser.userName,
email: pUser.email,
password: pUser.password
});
user.save(function(err, data) {
if(err) {
done(err);
} else {
done();
}
});
//it should then login that user with passport
});
});
If I connect o to mongoose directly:
mongoose.connect("mongodb://localhost/testing");
and require User this way:
User = require('../models/user');
It works.
I'd like to use the server and connection that the beforeEach sets up with kraken, so that inserts happen in the configured database...
Question is why does the mongoose insert never come back in the test?
You need to call mongoose.connect in your test code. mongoose queues all pending operations until a first db connection is made, which is why your save callback never gets called.
As noted by #Peter Lyons, I needed to perform the connect to the database.
I wrote a small helper to do this (that I can use across my test files).
db.js:
'use strict';
var nconf = require('nconf'),
mongoose = require('mongoose'),
env = process.env.NODE_ENV || 'testing';
//get the db config stuff for mongoose from the application config file
nconf.use('file', {
file: process.cwd() + '/config/app.json',
format: nconf.formats.json
});
var dbConf = nconf.get('databaseConfig')[env];
var db = function() {
return {
connect: function() {
if(!mongoose.connection.db) {
mongoose.connect("mongodb://" + dbConf.host + '/' + dbConf.database);
}
}
};
};
module.exports = db();
Then in my tests:
var db = require('./db');
db.connect();
And the model classes perform as expected.
How to connect to MongoDB with Node.js? And then pass the result to a client side JavaScript and display in HTML.
var http = require('http');
var URL = require('url');
var Db = require('mongodb').Db;
var Server = require('mongodb').Server;
var client = new Db('people', new Server("127.0.0.1", 27017, {}), { safe: false });
client.open(function (err, client) {
client.collection('people', listAllData);
});
var listAllData = function (err, collection) {
collection.find().toArray(function (err, results) {
console.log(results);
});
}
You should use Mongoose - elegant mongodb object modeling for node.js. http://mongoosejs.com
The quickstart guide is really cool, you should read it.
According to the documentation, here is a small example of how to use Mongoose:
var mongoose = require('mongoose');
var db = mongoose.createConnection('localhost', 'test');
var schema = mongoose.Schema({ name: 'string' });
var Cat = db.model('Cat', schema);
var kitty = new Cat({ name: 'Zildjian' });
kitty.save(function (err) {
if (err) // ...
console.log('meow');
});
I prefer MongoJS to Mongoose because it uses the same syntax used by the MongoDB Client syntax
https://github.com/gett/mongojs
// simple usage for a local db
var db = mongojs('mydb', ['mycollection']);
// the db is on a remote server (the port default to mongo)
var db = mongojs('example.com/mydb', ['mycollection']);
// we can also provide some credentials
var db = mongojs('username:password#example.com/mydb', ['mycollection']);
// connect now, and worry about collections later
var db = mongojs('mydb');
var mycollection = db.collection('mycollection');
Then you can use the same syntax as the Mongo Client
db.mycollection.find({}, function(err, docs) { ... });
db.mycollection.find({}).limit(2).skip(1, function(err, docs) { ... });
var n = new Chat();
n.name = "chat room";
n.save(function(){
//console.log(THE OBJECT ID that I just saved);
});
I want to console.log the object id of the object I just saved. How do I do that in Mongoose?
This just worked for me:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/lol', function(err) {
if (err) { console.log(err) }
});
var ChatSchema = new Schema({
name: String
});
mongoose.model('Chat', ChatSchema);
var Chat = mongoose.model('Chat');
var n = new Chat();
n.name = "chat room";
n.save(function(err,room) {
console.log(room.id);
});
$ node test.js
4e3444818cde747f02000001
$
I'm on mongoose 1.7.2 and this works just fine, just ran it again to be sure.
Mongo sends the complete document as a callbackobject so you can simply get it from there only.
for example
n.save(function(err,room){
var newRoomId = room._id;
});
You can manually generate the _id then you don't have to worry about pulling it back out later.
var mongoose = require('mongoose');
var myId = mongoose.Types.ObjectId();
// then set it manually when you create your object
_id: myId
// then use the variable wherever
You can get the object id in Mongoose right after creating a new object instance without having to save it to the database.
I'm using this code work in mongoose 4. You can try it in other versions.
var n = new Chat();
var _id = n._id;
or
n.save((function (_id) {
return function () {
console.log(_id);
// your save callback code in here
};
})(n._id));
Other answers have mentioned adding a callback, I prefer to use .then()
n.name = "chat room";
n.save()
.then(chatRoom => console.log(chatRoom._id));
example from the docs:.
var gnr = new Band({
name: "Guns N' Roses",
members: ['Axl', 'Slash']
});
var promise = gnr.save();
assert.ok(promise instanceof Promise);
promise.then(function (doc) {
assert.equal(doc.name, "Guns N' Roses");
});
Well, I have this:
TryThisSchema.post("save", function(next) {
console.log(this._id);
});
Notice the "post" in the first line. With my version of Mongoose, I have no trouble getting the _id value after the data is saved.
With save all you just need to do is:
n.save((err, room) => {
if (err) return `Error occurred while saving ${err}`;
const { _id } = room;
console.log(`New room id: ${_id}`);
return room;
});
Just in case someone is wondering how to get the same result using create:
const array = [{ type: 'jelly bean' }, { type: 'snickers' }];
Candy.create(array, (err, candies) => {
if (err) // ...
const [jellybean, snickers] = candies;
const jellybeadId = jellybean._id;
const snickersId = snickers._id;
// ...
});
Check out the official doc
Actually the ID should already be there when instantiating the object
var n = new Chat();
console.log(n._id) // => 4e7819d26f29f407b0... -> ID is already allocated
Check this answer here: https://stackoverflow.com/a/7480248/318380
As per Mongoose v5.x documentation:
The save() method returns a promise. If save() succeeds, the
promise resolves to the document that was saved.
Using that, something like this will also work:
let id;
n.save().then(savedDoc => {
id = savedDoc.id;
});
using async function
router.post('/create-new-chat', async (req, res) => {
const chat = new Chat({ name : 'chat room' });
try {
await chat.save();
console.log(chat._id);
}catch (e) {
console.log(e)
}
});