Mongoose or MongoDB for Schema definition? - node.js

Mongoose is used to define a schema. right?
Is it is possible to create a schema with mongoDB through mongo Shell ? like
eg: name:String

MongoDB doesn't support schema. It's a schemaless document based DB.
Mongoose is an ODM(Object Document Mapper) that helps to interact with MongoDB via schema, plus it also support validations & hooks.

Basically mongodb is schema less database we cant able to create schema directly in mongodb. Using mongoose we can able to create a schema. Simple CRUD operation using mongoose, for more info ref this link
package.json
{
"name": "product-api",
"main": "server.js",
"dependencies": {
"express": "~4.0.0",
"body-parser": "~1.0.1",
"cors": "2.8.1",
"mongoose": "~3.6.13"
}
}
product.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ProductSchema = new Schema({
title: String,
price: Number,
instock : Boolean,
photo : String ,
});
module.exports = mongoose.model('Product', ProductSchema);
// module.exports = mongoose.model('Product', ProductSchema,'optiponally pass schema name ');
server.js
var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors');
var app = express();
var mongoose = require('mongoose');
var product = require('./product');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var port = process.env.PORT || 8090;
var router = express.Router();
mongoose.connect('mongodb://localhost:27017/products');
// Middle Route
router.use(function (req, res, next) {
// do logging
// do authentication
console.log('Logging of request will be done here');
next(); // make sure we go to the next routes and don't stop here
});
router.route('/products').post(function (req, res) {
console.log("in add");
var p = new product();
p.title = req.body.title;
p.price = req.body.price;
p.instock = req.body.instock;
p.photo = req.body.photo;
p.save(function (err) {
if (err) {
res.send(err);
}
console.log("added");
res.send({ message: 'Product Created !' })
})
});
router.route('/products').get(function (req, res) {
product.find(function (err, products) {
if (err) {
res.send(err);
}
res.send(products);
});
});
router.route('/products/:product_id').get(function (req, res) {
product.findById(req.params.product_id, function (err, prod) {
if (err)
res.send(err);
res.json(prod);
});
});
router.route('/products/:product_id').put(function (req, res) {
product.findById(req.params.product_id, function (err, prod) {
if (err) {
res.send(err);
}
prod.title = req.body.title;
prod.price = req.body.price;
prod.instock = req.body.instock;
prod.photo = req.body.photo;
prod.save(function (err) {
if (err)
res.send(err);
res.json({ message: 'Product updated!' });
});
});
});
router.route('/products/:product_id').delete(function (req, res) {
product.remove({ _id: req.param.product_id }, function (err, prod) {
if (err) {
res.send(err);
}
res.json({ message: 'Successfully deleted' });
})
});
app.use(cors());
app.use('/api', router);
app.listen(port);
console.log('REST API is runnning at ' + port);

Mongoose helps to interact with MongoDB in terms of Object/Model so that programmer doesn't need to understand the remember the statements of MongoDB.
Also, Mongoose provides lot of methods of CRUD Operations to better understanding of DB Operations.
You can check examples here
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose
http://mongoosejs.com/docs/

Mongoose has its benefits of validation and schema configurations but it has its cons of latency and some problems with high/mid scale applications.
it's always the best thing IMHO, to use the native mongodb package.
regarding schema, you can create your own "schema" as a json file and write ur own validations for mandatory or valid attributes.
it's faster, with no third party packages and more reliable.

Related

mongoose required true req.body.name {}

If I set required to false, it will successfully create an object in the MongoDB database with one id. I suffer confusion sometimes, check my profile if you want. I think it's a little thing. If you need more info, just comment.
app.js
var express = require('express');
var bodyParser = require('body-parser');
var product = require('./routes/product'); // Imports routes for the products
var app = express();
var mongoose = require('mongoose'); // Set up mongoose connection
var dev_db_url = 'mongodb://localhost/Product';
var mongoDB = process.env.MONGODB_URI || dev_db_url;
mongoose.connect(mongoDB, {useNewUrlParser: true, useUnifiedTopology: true});
mongoose.Promise = global.Promise;
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use('/products', product);
var port = 3002;
app.listen(port, () => {
console.log('Server is up on port numbner ' + port);
});
model.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ProductSchema = new Schema({
name: {type: String, required: true, max: 100},
price: {type: Number, required: true},
});
module.exports = mongoose.model('Product', ProductSchema);
controller.js
var Product = require('../models/product');
//Simple version, without validation or sanitation
exports.test = function (req, res) {
res.send('Greetings from the Test controller!');
};
exports.product_create = function (req, res, next) {
var product = new Product(
{
name: req.body.name,
bags: req.body.bags
}
);
console.log(JSON.stringify(req.body))
product.save(function (err) {
if (err) {
return next(err);
}
res.send('Bags Created successfully')
})
};
router.js
var express = require('express');
var router = express.Router();
// Require the controllers WHICH WE DID NOT CREATE YET!!
var product_controller = require('../controllers/product');
// a simple test url to check that all of our files are communicating correctly.
router.get('/test', product_controller.test);
router.post('/create', product_controller.product_create);
module.exports = router;
HTTP POST: http://localhost:3002/products/create?name=Jorge&price=20
ValidationError: Product validation failed: name: Path name is
required
Can you help?
Thanks!
💡 The reason why it's error, because your req.body.name is empty or null. Why it's null or empty or undefined? Because you're not add your data in your body, when you send create request.
You can see your Endpoint:
HTTP POST: http://localhost:3002/products/create?name=Jorge&price=20
It's not about req.body, it's a req.params. So you can use req.params.name and req.params.price.
🕵️‍♂️ So, If you're passing your data using parameres, your code will looks like this:
exports.product_create = function (req, res, next) {
var product = new Product(
{
name: req.params.name,
price: req.params.price
}
);
console.log(req.params);
product.save(function (err) {
if (err) {
return next(err);
}
res.send('Bags Created successfully')
})
};
If you want to use req.body, than add your json object tobody if you're using Postman.
🕵️‍♂️ You can see the image below: An example using postman to passing your data into body, before you send create request to your backend.
So, If You're passing your data from body, than your code will looks like this:
exports.product_create = function (req, res, next) {
var product = new Product(
{
name: req.body.name,
price: req.body.price
}
);
console.log(req.body);
product.save(function (err) {
if (err) {
return next(err);
}
res.send('Bags Created successfully')
})
};
I hope it's can help you.

Mongoose doesn't save documents to my database locally

My problem is simple as i guess.
i can run mongoose to save documents to my DB on mlab.
also can see the saved data via postman on get requests.
but when i use local mongodb instead of mlab then try to show the db collections on my terminal by running "mongo" then select the same db to which mongoose is connected
it shows me an empty db.
i try again to send post request with new data.. and the result is same, positive on postman and mlab, but when connect to local mongodb and post new data.. there is nothing there at all. the only way i can insert data to my shell is through the command insert().
Any idea why is this happening?
Thank you in advance.
app.js
var express = require("express");
var app = express();
var port = 8080;
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
var mongoose = require("mongoose");
mongoose.Promise = global.Promise;
mongoose.connect("mongodb://localhost:27017/test",{ useNewUrlParser: true });
// Model & Schema
var nameSchema = new mongoose.Schema({
firstName: String,
lastName: String
});
var User = mongoose.model("User", nameSchema);
// Routes
app.get('/users', (req, res) => {
User.find({}, (err, user) => {
if (err) throw err;
console.log(user)
res.send(user)
})
})
app.post("/addname", (req, res) => {
var myData = new User(req.body);
myData.save()
.then(item => {
res.send("item saved to database");
})
.catch(err => {
res.status(400).send("unable to save to database");
});
});
app.use("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
app.listen(port, () => {
console.log("Server listening on port " + port);
});
Here when i use mlab:
BUT when using local machine..:
try like below in add api
app.post("/addname", (req, res) => {
req.body = JSON.parse(JSON.stringify(req.body)); //This line is Optional, some time req.body is in json buffer form so we are converting to pure json
User(req.body).save().then(item => {
console.log("DB Item saved --->", item);
res.status(200).send("item saved to database");
}).catch(err => {
res.status(400).send("unable to save to database");
});
});
dont forget that req.body must contain firstName, lastName
After your Question update regarding the listing of Collection(Schema) Documents
Your are trying
db.test.find()
which will not work because Your Schema name is User and will save as users since mongodb prefer Plural collection names because it consists of more than One Documents
You must try
db.users.find() in your mongo shell
It will return all documents of User Collections.
If you want specific collection name(Schema name) then you have to create schema as below
// Model & Schema
var nameSchema = new mongoose.Schema({
firstName: String,
lastName: String
}, { collection: 'User' });
var User = mongoose.model("User", nameSchema);
In mongo shell you must try like
db.User.find();
For listing all collection in mongo shell you must try like below
db.getCollectionNames()

How to use nodejs RESTful api to query from multiple collections?

nodejs noobie here,
I have created nodejs RESTful api for fetching data from three different collections. Here is the article which helped me nodejs api in 10 minutes
After creating APIs, I am able to hit the APIs through postman and get data there. Now I wish to move on to next step of querying records from multiple collections
Server.js
var express = require('express'),
app = express(),
port = process.env.PORT ||3000,
mongoose = require('mongoose'),
menu = require('./app/api/bestseller_books/models/bestsellerBooksModel'),
admin = require('./app/api/admin/models/adminModel'),
test = require('./app/api/test/models/testModel'),
bodyParser = require('body-parser');
var Schema = mongoose.Schema;
var cors = require('cors');
// mongoose instance connection url connection
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost:27017/takebook', { useMongoClient: true });
/*mongoose.model('menu', new Schema({ title: String, id: Number }));*/
var menu = mongoose.model('bestseller_books');
var test = mongoose.model('test');
var admin = mongoose.model('admin');
var routes = require('./app/api/bestseller_books/routes/bestsellerBooksRoutes');
var routes2 = require('./app/api/admin/routes/adminRoutes');
var routes3 = require('./app/api/test/routes/testRoutes');
menu.find({}, function(err, data) { console.log(err, data.length); });
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
routes(app); //register the route
/*routes2(app);
routes3(app);*/
app.listen(port);
app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'})
});
console.log('RESTful API server started on: ' + port);
bestsellerbooks controller
'use strict';
var mongoose = require('mongoose'),
menu = mongoose.model('bestseller_books');
exports.list_all_menus = function(req, res) {
menu.find({}, function(err, menu) {
if (err)
res.send(err);
res.json(menu);
console.log(res);
});
};
exports.create_a_menu = function(req, res) {
var new_menu = new menu(req.body);
new_menu.save(function(err, menu) {
if (err)
res.send(err);
res.json(menu);
});
};
exports.read_a_menu = function(req, res) {
menu.findById(req.params.menuId, function(err, menu) {
if (err)
res.send(err);
res.json(menu);
});
};
exports.update_a_menu = function(req, res) {
menu.findOneAndUpdate({_id: req.params.menuId}, req.body, {new: true}, function(err, menu) {
if (err)
res.send(err);
res.json(menu);
});
};
exports.delete_a_menu = function(req, res) {
menu.remove({
_id: req.params.menuId
}, function(err, menu) {
if (err)
res.send(err);
res.json({ message: 'bestseller_books successfully deleted' });
});
};
My questions are :
Do I have to create new set of models, controllers and routes for
each API?
Looking at the server.js, is this the best practice of
setting up API routes?
What is the use of create_a_menu methods
mentioned in API controllers, if I have to hit API in this format:
app.controller('booklister', ['$http', function($http) {
var self = this;
$http.get('http://localhost:3000/bestseller_books')
.then(function(response)
{
/*$('.fa-refresh').hide();*/
self.items = response.data;
}, function(errResponse) {
/*$('.fa-refresh').show();*/
console.error('Service Error while fetching books' + errResponse);
});
Just create more from everything.
New model, new schema, new Bl layer, new route that take care for that new collection.
For example:
In yore dotsModel.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var DotsSchema = new Schema({
x: {
type: Number
},
y: {
type: Number
}
});
module.exports = mongoose.model('Dots', DotsSchema);
In youre dotsController.js:
var mongoose = require('mongoose'),
Dots = mongoose.model('Dots')
exports.get_all_dots = function (req, res) {
Dots.find({}, function (err, task) {
if (err)
res.send(err);
res.json(task);
});
};
And in your dotsRoutes.js:
module.exports = function(app) {
var todoList = require('../controllers/ dotsController.js:');
app.route('/dots')
.get(todoList.get_all_dots);
Note:
The article you read is short and he touch really briefly on each topic, it's highly recommended to take another course, much longer, and take the time to learn each part of your application, and what node capable of.

Validation failed nodejs required field

I am creating creating a bookstore demo app in Node.js. I have ran into a little situation with the POST request for creating a genre. I've setup so the name of the genre must be required if not don't insert it to the database. But when I use Postman to POST to the url localhost:3000/api/genres with the JSON
{
"name": "TEST"
}
It throws an error
{
"error": "Genre validation failed"
}
When I remove the required field in the genreSchema it works but the name of the genre doesn't appear. Here is my code
Code:
genre.js
var mongoose = require("mongoose");
// Create a schema for genre
var Schema = mongoose.Schema;
var genreSchema = Schema({
name:{
type: String,
required: true
},
create_date:{
type: Date,
default: Date.now
}
});
var Genre = module.exports = mongoose.model("Genre", genreSchema);
// Methods
// get genres
module.exports.getGenres = function(callback, limit) {
Genre.find(callback).limit(limit);
};
// add a new genre
// TODO: Not working in Postman ValidationError
module.exports.addGenre = function(genre, callback) {
Genre.create(genre, callback);
};
app.js
var express = require("express");
var app = express();
var bodyParser = require("body-parser");
var mongoose = require("mongoose");
var Genre = require('./models/genre');
var Book = require('./models/book');
// Connect to mongoose
mongoose.connect("mongodb://localhost/bookstore");
var db = mongoose.connection;
app.get("/", function(req, res){
res.json({ error: "Please use /api/books or /api/genres" });
});
// GET /api/genres
app.get('/api/genres', function(req, res){
Genre.getGenres(function(err, genres){
if(err) {
res.json({error: err.message})
}
res.json(genres);
});
});
app.post('/api/genres', function(req, res){
var genre = req.body;
Genre.addGenre(genre, function(err, genre){
if(err) {
res.json({
error: err.message
})
}
res.json(genre);
});
});
// GET /api/books
app.get('/api/books', function(req, res){
Book.getBooks(function(err, books){
if(err) {
res.json({error: err.stack})
}
res.json(books);
});
});
// GET /api/book/:id
app.get('/api/book/:_id', function(req, res){
Book.getBookById(req.params._id, function(err, book){
if(err) {
res.json({error: err.message})
}
res.json(book);
});
});
app.listen(3000, function(){
console.log("Running on port 3000!")
});
Have you tried console.log(req.body); inside your post route? I don't think you've setup body-parser as middleware so req.body is coming in empty and therefore not sending anything to your Genre.addGenre method.

When I use mongoose & connect MongoDB, I can insert and get data. But unable to find data using MongoClient

My code as follows. Open localhost/users/,brower return
{"_id":"55519446e063d4c409f93f00","username":"justnode","__v":0}
but when I open mongo shell and input: use student and db.student.find(),I can't find anything. My MongoDB version is 3.0.1 and nodejs version is 0.12.2, OS is Centos 6.4
var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var app = express();
mongoose.connect('mongodb://localhost/student', function (error) {
if (error) {
console.log(error);
}
});
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: {type: String, unique: true}
});
var UserModel = mongoose.model('UserModel', UserSchema);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
/*
post content as follows
{
"username": "justnode"
}
*/
app.post('/users/create', function (req, res) {
console.log("in /users/create");
var userModelJson = req.body;
var userModel = new UserModel(userModelJson);
userModel.save(function(error) {
if(error) {
console.log(error);
return res.json({msg: "error"});
}
console.log("user created: " + userModel.username);
res.json(userModel);
});
});
/*
open localhost/users/ brower return {"_id":"55519446e063d4c409f93f00","username":"justnode","__v":0}]
but when I open mongo client: db.student.find() i can't find anything
*/
app.get('/users', function (req, res) {
UserModel.find({}, function (err, docs) {
res.json(docs);
});
});
var serverApp = app.listen(80, function () {
console.log('Express server listening on port ' + serverApp.address().port);
});
Change database(student), schema(UserSchema) and model(UserModel)'s name and try it again. My case, after changing the variable's name and restart, it works. (I've no idea why, maybe mongoose or mongo shell has some bug?)

Resources