I am currently working on a small personal multiplayer game project. I am using node.js along with express.js, mongoose and socket.io. It is my first project with JavaScript, I come from a C/C++ background.
The question is:
Whether some kind of generic requiring is possible:
I have currently a models folder in my project root and all the mongoose models are in there,
they all look similar to this one:
function make(Schema, mongoose) {
var UserSchema = new Schema({
name : String
, passwd : String
, is_online : Boolean
, socket_id : Number
});
mongoose.model('User', UserSchema);
}
module.exports.make = make;
If I remember right, I found this approach somewhere on stackoverflow. Now when I am starting the node.js application, I have to connect to the database and then have to call all the make functions.
Is there a generic way to do that?
Somethink like this (pseudo-code):
models = require('./models/');
for each m in models do
{
m.make(Schema, mongoose);
}
I do it a little different:
var UserSchema = new Schema({
name : String
, passwd : String
, is_online : Boolean
, socket_id : Number
});
module.exports = mongoose.model('User', UserSchema);
Now I can require the model and use it right away like this:
var userModel = require('models/user');
userModel.find()//...
Related
I am creating an api, and i'm working with MongoDB as a dataBase,
I've already created one model :
in database.ts
import mongoose = require('mongoose');
const schema = new mongoose.Schema({
id: String,
username: String,
gender: String,
birthdate: String,
password: String
});
export default mongoose.model('users', schema);
i'm connecting to the database using :
mongoose.connect('mongodb://localhost:27017/users', {useNewUrlParser: true});
in app.ts.
In utils.ts I imported the model like this :
import userDB from './database';
and for example, to retrieve all the users inside the database I use this (still in utils.js) :
const users = await userDB.find();
Now my problem is that I want to have another model, which will have some keys insides, that I can retrieve and check if for example what the user has given to me correspond to one of the keys
I tried to search on most of the websites but didn't find the right answer.
I hope you can help me.
Thanks you in advance.
PS: it's my first post here, so if I did something wrong or my problem is not clear, feel free to tell me
When you are connecting to Database you should connect to a project rather than to your schema like this
mongoose.connect('mongodb://localhost:27017/myProject', {useNewUrlParser: true});
You can replace myProject with whatever name you like. If the Project doesn't exist it will be created once you start your server and mongoDB is connected.
Then to retrieve all the users you can use this
import User from './user'; //Wherever your schema is
const Allusers = await User.find();
Now you can create as many Schema's you like and use it.
I have a problem and could really use some help.
We had an application that used MySQL and we are switching over to MongoDB.
We are using Node.js with Express and have MongoDB and Mongoose for the database
We have looked at the MongoDB and Mongoose documentation and searched for related questions on Stack Overflow but we seem to be missing something.
This is what we have in app.js:
var mongo = require('mongodb');
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost:27017/DBName');
This is our usersModel.js
var db = require('mongoose');
var Schema = db.Schema;
var userSchema = new Schema({
u_id : Number,
u_name : { type: String, required: true },
u_lastname : String
});
module.exports = db.model('user', userSchema);
And this is what we use in the userController:
var User = require('../models/usersModel');
User.find({}, function(err, users) {
if (err) throw err;
console.log("Found users: ", users);
});
The console.log(db.connection.readyState); says it is connecting.
And the User.find() doesn't seem to give out an error, but instead gives an empty array/undefined.
We would really appreciate it if someone could tell us what we overlook.
Thanks in advance.
Not sure why anyone thought this was a good idea, but here's what mongoose does:
Mongoose by default produces a collection name by passing the model name to the utils.toCollectionName method. This method pluralizes the name.
As a bonus, it's in lower-case which sucks when you have table names with camel case convention.
You can fix it by setting below option in your scheme:
var userSchema = new Schema({..}, { collection: 'user' });
More on this here.
Your find() call looks fine to me.
Are you sure there are users in your collection? Does creating a new user throw an error that you didn't notice? Maybe you can verify that there are indeed users in your collection by popping open a terminal and writing:
> mongo
> use DBName
> show collections
> db.user.find()
And that will return all users that exist.
At: iuliu.net: We get both errors the first was [] and the second is undefined.
At JohnnyHK: Thank you for your submit, but we are sure the the user collection is in this database and the properties we search exists.
At Juuso: Thanks for your feedback your but in the mongo terminal we got the collection output.
Some one asked us a critical question if we tried this with monk. We
installed monk and we have find the database, collection and got
result back. We're still not sure what the problem with Mongoose was,
but with monk it works.
Thank you guys for your feedback and time.
need a little assistance with an understanding nodejs code organization,
so I'm from C++ world and suppose that didn't understand a principles.
So I need to implement some js module which should connect to MongoDB and exports a few methods for other modules: e.g. insert, update, delete.
when I write something like:
var db = MongoClient.connect(config.connectionString, {native_parser:true},function (err, db) {...});
exports.insert = function(a, b) {
// db using
//...
};
I suppose that "db" local static variable and will be initialized in any case. at the time of call "require('this module') " but seems it's not so, and db is uninitialized at the time of the call of exported functions? another question - I suppose this should be implemented using "futures" (class from c++, didn't find an analogue from js) to guaratee that db object is copmpletely constructed at the moment of the using??
So the problem I see is that you want to use DB but since DB is returned async, it may or may not be available in the exported function, hence you need to convert the connect from async to sync.
Since MongoDB driver cannot do sync, i suggest you use a wrapper, i suggest mongoskin.
https://github.com/kissjs/node-mongoskin
var mongo = require('mongoskin');
var db = mongo.db(config.connectionString, {native_parser:true});
Now this should work for you.
I had worked with C++, Java before (sometime back, not now) and now working in nodejs. I think I understood your question. Here are some key points.
Yes, Nodejs modules are somewhat like classes that they encapsulate the variables and you access only through public methods (exposed through exports). I think you are aware that there is no class implementation at all here, but it loosely maps to the behaviour.
The key difference in nodejs is the asynchronous nature of resource instantiation. By this, I mean if there are 2 statements stmt1 and stmt2, if stmt1 is called and takes time, nodejs does not wait for it to end (that is synchronous behaviour), instead it moves on to stmt2. In pre-nodejs world, we assume that reaching stmt2 means stmt1 is complete.
So, what is the workaround? How to ensure you do something after db connection is obtained. If your code is not making db calls immediately, you could assume that connection will be through. Or if you immediately want to invoke db, you write the code on a callback. Mongo exposes events called 'open' and 'error'. You can use this to ensure connection is open. Also it is best practise to track error event.
db.on('error', console.error.bind(console, 'connection error'));
db.once('open', function callback() {
console.log("Connection with database succeeded.");
// put your code
});
I am not aware of C++ future and so cannot comment on that.
Hope this helps !
[Updated] To add example
You could have db.js for setting up db connection and expose Mongoose object to create models.
'use strict';
var Mongoose = require('mongoose'),
Config = require('./config');
Mongoose.connect(Config.database.url);
var db = Mongoose.connection;
db.on('error', console.error.bind(console, 'connection error'));
db.once('open', function callback() {
console.log("Connection with database succeeded.");
});
exports.Mongoose = Mongoose;
exports.db = db;
You can include db.js in the server.js like
var DB = require('db.js');
which will do the initialisation.
You then use mongoose (mongoose is a Object relational mapper to work with mongo and highly recommended) to get models of database objects as shown below.
//userModel.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
var UserSchema = new Schema({
uid : {type : Number, required: false}
, email : {type : String, get: toLower, set: toLower, required: true, index: { unique: true } }
, passwd : {type : String, required: false}
);
var user = mongoose.model('user', UserSchema);
module.exports = {
User : user
};
For more information on mongoose, you can refer http://mongoosejs.com
The db is generally not closed as I use in web environment and is always on. There is db connection pooling maintained and connections are reused optimally. I saw noticed a thread in SO which adds more details. Why is it recommended not to close a MongoDB connection anywhere in Node.js code?
I started taking some tutorials and some books about NodeJS, and started to test out stuff using Mongoose and Rest API requests.
The problem that I encountered is related to the creation of a constructor which will take a parameter (requestBody) and then implement the whole binding on the module (on my case user.js). That is to make the code more reusable and the user module to handle the bindings not the server module which will increase the source code a lot there.
Example
The code below is working as it should, but it's not efficient
var express = require('express')
, bodyParser = require('body-parser')
, expressValidator = require('express-validator')
, mongoose = require('mongoose');
var router = express.Router();
router.route('/users')
// Create a user (accessed at POST http://localhost:8080/api/users)
.post(function (req, res) {
// Bind user (repeating the same procedure for every User object)
var user = new User();
user.info.name = req.info.name;
user.info.surname = req.info.name;
.... // around 10 other properties
req.info.birthday = req.info.name;
// Save
user.save(function (err) {
.... // Handling completion
});
})
My approach
// app/models/user.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
info: {
name: {type: String, required: true},
surname: {type: String, required: true},
......
birthday: {type: String, required: true}, // dd/mm/yyyy
},
likes: [Schema.Types.ObjectId],
dislikes: [Schema.Types.ObjectId]
});
function initUser(model) {
userSchema.info.name = model.info.name;
userSchema.info.surname = model.info.surname;
......
userSchema.info.birthday = model.info.birthday;
userSchema.likes = model.likes;
userSchema.dislikes = model.dislikes;
}
module.exports = mongoose.model('User', userSchema);
module.exports.initUser = initUser;
Based on this code, on the request I could easily use (Javascript beginner so explanation will be great)
var user = new User();
user.initUser(req);
but I come up with a really long error which causes the server to crash and the cleanest message is:
TypeError: Converting circular structure to JSON
Questions
Is there anyone who has solved this? I also took a look at Mongoose site, but there doesn't seem to have a specific thing like this.
I'm not sure about your circular json problem, but your initial problem is the way in which you are reading your model properties off your request.
If you post values to that endpoint, the json values you are looking for are going to be on the body property on the request. Pass your function this:
user.initUser(req.body)
You'll need to install a body parser in express to handle the value properly. Once you've done that and pass in request.body, your approach will work.
Pro tip: don't bother mapping the properties individually. If the keys are correctly named just use them to construct your model directly.
Im building a simple web app app in express, and I'm a bit stuck in the authentification for my sessions, im going to validate everything in the client with backbone and regExp eventually when i start building the front end of the app. no basycally i have an issue with the query in mongoose returning a mongoose document object. I've looked up a couple of solutions, in the query you can use a .lean() to get an object, or grab the return from the query and apply a .toObject(), that all works fine and dandy, however when i try and authenticate the value of the key with a string it returns false. i'll post an example code, its not exactly what i've got, but its close enough to get the point across.
this would be an example of my models file
var User = new Schema({}, { strict: false });
User.method('authenticate', function(plainText) {
var object = this.toObject();
return plainText == object.password; });
mongoose.model('User', User);
mongoose.connect( definitions.dbConnect );
and in my app file i would have something like
app.get('/session', routes.showLogin);
app.post('/session/new', routes.login);
and in my routes file id have something like
exports.login = function(req, res){
var userQuery = new RegExp(req.body.username , 'i');
var passwordQuery = new RegExp(req.body.password, 'i');
var Query = User.find();
Query.findOne().where('username', userQuery).exec(function(err, user){
if(user && user.authenticate((req.body.password))){
req.session.userId = user._id;
}else{
res.redirect('/session');
}
});
},
Any ideas would be appreciated, its probably very silly... : /
Thanks in advanced!
YEah robert klep was right on the money, After i seearched the mongoose Documentation and the mongodb docs as well, it became clear that queries return a mongo document object, in terms should be converted to the same object or variable types for opperands to work.