I'm trying to build an API with Express and Waterline ORM. The adapter I'm using is mongodb-adapter. The reason I'm trying to do this from outside Sails is that I want better understand the Waterline ORM so I can contribute to the Sails Couch Adapter. Here's what I got.
var express = require('express'),
app = express(),
bodyParser = require('body-parser'),
methodOverride = require('method-override'),
Waterline = require('waterline');
var mongoAdapter = require('sails-mongo');
app.use(bodyParser());
app.use(methodOverride());
mongoAdapter.host = 'localhost';
mongoAdapter.schema = true;
mongoAdapter.database = 'waterline-mongo';
app.models = {};
var User = Waterline.Collection.extend({
adapter:'mongodb',
// identity: 'user',
attributes: {
first_name: 'string',
last_name: 'string'
}
});
app.post('/users', function(req, res) {
console.log(req.body);
app.models.user.create(req.body, function(err, model) {
if(err) return res.json({ err: err }, 500);
res.json(model);
});
});
new User({ adapters: { mongodb: mongoAdapter }}, function(err, collection) {
app.models.user = collection;
// Start Server
app.listen(3000);
console.log('Listening on 3000');
});
So from what I understand collection will have the create/update/destory methods as defined by the Waterline API. However when I post to /users, I get a 'cannot call method "create" of undefined. The version of Waterline I'm using is 0.9.16. I'm probably setting this up wrong. Thanks in advance.
You'll have to add these instructions:
var orm = new Waterline();
var config = {
// Setup Adapters
// Creates named adapters that have have been required
adapters: {
'default': 'mongo',
mongo: require('sails-mongo')
},
// Build Connections Config
// Setup connections using the named adapter configs
connections: {
'default': {
adapter: 'mongo',
url: 'mongodb://localhost:27017/unparse'
}
}
};
var User = Waterline.Collection.extend({
identity: 'user',
connection: 'default',
attributes: {
first_name: 'string',
last_name: 'string'
}
});
orm.loadCollection(User);
orm.initialize(config, function(err, data) {
if (err) {
throw err;
}
app.models = data.collections;
app.connections = data.connections;
app.listen(3000);
});
Related
I'm trying to use raw queries from sequelize in an express app.
My folder structure is:
/
/index.js
/models/index.js
/models/price.js
/controllers/price.js
I want to use sequelize which I already define in /models/index.js from a controller.
This is /models/index.js:
"use strict";
var fs = require("fs");
var path = require("path");
var Sequelize = require('sequelize')
, sequelize = new Sequelize(process.env.MYSQL_DB, process.env.MYSQL_USER, process.env.MYSQL_PASSWORD, {
dialect: "mysql", // or 'sqlite', 'postgres', 'mariadb'
port: 3306, // or 5432 (for postgres)
timezone:'America/Sao_Paulo',
});
sequelize
.authenticate()
.then(function(err) {
console.log('Connection has been established successfully.');
}, function (err) {
console.log('Unable to connect to the database:', err);
});
var db = {};
fs
.readdirSync(__dirname)
.filter(function(file) {
return (file.indexOf(".") !== 0) && (file !== "index.js");
})
.forEach(function(file) {
var model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(function(modelName) {
if ("associate" in db[modelName]) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
module.exports.db = db;
I want to use a raw query in my price controller:
exports.index = function(req, res, next) {
// var environment_hash = req.session.passport.user.environment_hash;
var Price = require('../models/index').Price;
var db = require('../models/index').db;
console.log(db);
db.query(`SELECT ... `).spread((results, metadata) => {
// Results will be an empty array and metadata will contain the number of affected rows.
console.log(results);
});
var values = {
where: { symbol: 'xxx' },
};
Price
.findOne(values)
.then(function(price) {
console.log("found!!!!!");
console.log(price);
res.render('home/home.ejs', {
price: price
});
});
};
But I'm getting this error message:
db: [Circular] }
TypeError: db.query is not a function
How can I fix this?
The Sequelize library is being assigned to a variable on the db object.
The error is in the second file instead of calling
db.query
We should call
db.sequelize.query
In the first case we have called a function that does not exist. In another case we could assign the query function to a property on the db object.
db.query = db.sequelize.query
or you can de-structure using ES6
db.query = { query } = db.sequelize
Now we can run db.query as expected.
I have been having trouble accessing the data that is passed to express restful service from angular http service.(i build this web app with angular + node + express + mongodb)
While I using angular to post data to rest service, it cannot get my post json data, but when I using POSTMAN to post the data then it is working....
how can it be ?
is anything I missing in restful server side??
this is reply when angular post json
{
__v: 0,
_id: "59e854e9895ea424b40471a9",
updateTime: "2017-10-19T07:31:53.301Z",
createTime: "2017-10-19T07:31:53.301Z"
}
this is reply when postman post json
{
"__v": 0,
"uuid": "123",
"major": 10029,
"minor": 18910,
"bluetoothAddress": "123",
"createBy": "root",
"updateBy": "root",
"_id": "59e852ab4297be32902bae1d",
"updateTime": "2017-10-19T07:22:19.417Z",
"createTime": "2017-10-19T07:22:19.417Z"
}
this is my angular side code
controller.js
$scope.submitNewIbeacon = function() {
let data = {
uuid: $scope.inputUUID,
major: parseInt($scope.inputMajor),
minor: parseInt($scope.inputMinor),
bluetoothAddress: $scope.inputBluetoothAddress,
createBy: $scope.loginUser,
updateBy: $scope.loginUser
}
IbeaconListService.create_a_ibeacon(data)
.then(
function(response) {
var newIBeacon = response.data;
});
}
service.js
app.service('IbeaconListService', ['$http', '$q', function($http, $q) {
var BASEURL = "http://localhost:3000";
this.create_a_ibeacon = function(data) {
var deferred = $q.defer();
var config = {
headers: {
'Content-Type': 'application/json;charset=utf-8;'
}
}
$http.post(BASEURL + "/ibeacons", data, config)
.then(function(data) {
deferred.resolve(data);
}, function(error) {
deferred.reject(error);
})
return deferred.promise;
}
}]);
and this is my nodejs code
server.js
const express = require('express'),
app = express(),
port = process.env.PORT || 3000,
fileUpload = require('express-fileupload'),
cors = require('cors'),
mongoose = require('mongoose'),
ibeacon = require('./api/models/ibeaconListModel'),
area = require('./api/models/areaListModel'),
bodyParser = require('body-parser');
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
// mongoose instance connection url connection
mongoose.Promise = global.Promise;
// connect to MongoDB and create/use database called IbeaconDB
mongoose.connect('mongodb://localhost/IbeaconDB');
//importing route
var ibeaconRoutes = require('./api/routes/ibeaconListRoutes.js');
var areaRoutes = require('./api/routes/areaListRoutes.js');
//register the route
ibeaconRoutes(app);
areaRoutes(app);
app.listen(port);
console.log('ibeacon RESTful API server started on: ' + port);
app.use(function(req, res) {
res.status(404).send({ url: req.originalUrl + ' not found' })
});
ibeaconListModel.js
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var IbeaconSchema = new Schema({
uuid: {
type: String
},
major: {
type: Number
},
minor: {
type: Number
},
bluetoothAddress: {
type: String
},
createBy: {
type: String
},
createTime: {
type: Date,
default: Date.now
},
updateBy: {
type: String
},
updateTime: {
type: Date,
default: Date.now
}
});
// create a model based on the schema
module.exports = mongoose.model('Ibeacons', IbeaconSchema);
ibeaconListRoutes.js
'use strict';
module.exports = function(app) {
var ibeaconList = require('../controllers/ibeaconListController');
// ibeaconList Routes
app.route('/ibeacons')
.get(ibeaconList.list_all_ibeacons)
.post(ibeaconList.create_a_ibeacon);
app.route('/ibeacons/:ibeaconId')
.get(ibeaconList.read_a_ibeacon)
.put(ibeaconList.update_a_ibeacon)
.delete(ibeaconList.delete_a_ibeacon);
};
ibeaconListController.js
'use strict';
var mongoose = require('mongoose'),
Ibeacon = mongoose.model('Ibeacons');
exports.list_all_ibeacons = function(req, res) {
Ibeacon.find({}, function(err, ibeacon) {
if (err)
res.send(err);
res.json(ibeacon);
});
};
exports.create_a_ibeacon = function(req, res) {
const doc = {
uuid: req.body.uuid,
major: req.body.major,
minor: req.body.minor,
bluetoothAddress: req.body.bluetoothAddress,
updateBy: req.body.updateBy,
createBy: req.body.createBy
}
var new_ibeacon = new Ibeacon(doc);
console.log(new_ibeacon);
new_ibeacon.save(function(err, ibeacon) {
if (err)
res.send(err);
res.json(ibeacon);
});
};
exports.read_a_ibeacon = function(req, res) {
Ibeacon.findById(req.params.ibeaconId, function(err, ibeacon) {
if (err)
res.send(err);
res.json(ibeacon);
});
};
exports.update_a_ibeacon = function(req, res) {
const doc = {
uuid: req.body.uuid,
major: req.body.major,
minor: req.body.minor,
bluetoothAddress: req.body.bluetoothAddress,
updateBy: req.body.updateBy,
updateTime: Date.now()
}
Ibeacon.findOneAndUpdate({ _id: req.params.ibeaconId }, doc, { new: true }, function(err, ibeacon) {
if (err)
res.send(err);
res.json(ibeacon);
});
};
exports.delete_a_ibeacon = function(req, res) {
Ibeacon.remove({
_id: req.params.ibeaconId
}, function(err, ibeacon) {
if (err)
res.send(err);
res.json({ message: 'Ibeacon successfully deleted' });
});
};
Update 10:29pm
I use custom middleware to check my request, then I found that my http method is GET ( it suppose to be POST )
Custom Middleware
app.use((req,res,next) => {
console.log(req);
next();
});
very confused ##
I am trying to write a REST backend using Node.js, express and MongoDB but am having some issues creating PUT calls for some reason. The issue is with app.post('/contacts/add', contacts.addContacts) as it works fine if I change it to GET but when I change it to either PUT or POST I get the error Cannot GET /contacts/add Any ideas?
I am using express 4.15.3, mongodb 3.4.5 and npm 4.2.0
server.js:
var express = require('express'),
contacts = require('./routes/contacts');
bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.get('/contacts/chalkboard/:id', contacts.getChalkboardContacts);
app.get('/contacts/get/:uid', contacts.getContacts);
app.post('/contacts/add', contacts.addContacts);
app.listen(3000);
console.log('Listening on port 3000...');
contacts.js
var mongo = require('mongodb');
mongo.BSONPure = require('bson').BSONPure;
var Server = mongo.Server,
Db = mongo.Db,
BSON = mongo.BSONPure;
var server = new Server('localhost', 27017, {auto_reconnect: true});
db = new Db('db', server);
db.open(function(err, db) {
if(!err) {
console.log("Connected to database");
db.collection('contacts', {strict:true}, function(err, collection) {
if (err) {
console.log("The 'contacts' collection doesn't exist. Creating it with sample data...");
populateDB();
}
});
}
});
exports.getChalkboardContacts = function(req, res) {
var uid = req.params.uid.toString();
var date = new Date();
var timeInMs = date.getMilliseconds();
console.log(uid);
db.collection('contacts', function(err, collection) {
console.log('collection: ' + collection);
collection.find({uid: uid, lastMessage: {$gte: timeInMs}}).toArray(function(err, items) {
res.send(items);
});
});
};
exports.getContacts = function(req, res) {
var uid = req.params.uid.toString();
console.log(uid);
db.collection('contacts', function(err, collection) {
console.log('collection: ' + collection);
collection.find({uid: uid}).toArray(function(err, items) {
res.send(items);
});
});
};
exports.addContacts = function(req, res) {
console.log('working');
db.collection('contacts', function(err, collection) {
var id = "592159bc3e48764418170399";
var contact = {uid: "592159bc3e48764418173333",
keyUid: "592159bc3e48764418171444",
name: "Billy Jean",
phoneNumber: "+491721894733",
battery: "47%", longitude: "0",
latitude: "0",
city: "city",
country: "country",
place: "place",
address: "address",
lastMessage: "lastMessage",
lastUpdated: "lastUpdated"};
collection.update({'uid':id}, {$push:{'contacts':contact}}, function(err, result) {
if (err) {
console.log('Error updating contact: ' + err);
res.send({'error':'An error has occurred'});
} else {
console.log('' + result + ' document(s) updated');
res.send(result);
}
});
});
};
I didn't spot anything immediately wrong with the code.
You might be falling into a very common pitfall when using body-parser for JSON. Your request must specify Content-Type: application/json in the request for the parser to parse it. Otherwise, it won't work.
If that doesn't do the trick, if you can share any error messages or response codes you get, it may illuminate another issue.
I'm studying Node.js + Express, coding a basic login example. My /login route is set inside the routes/login.js file:
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var connectionpool = mysql.createPool({
host : 'localhost',
user : 'user',
password : 'pass',
database : 'database'
});
router.post('/', function(req,res){
connectionpool.getConnection(function(err, connection) {
if (err) {
console.error('CONNECTION error: ',err);
res.statusCode = 503;
res.send({
result: 'error',
err: err.code
});
} else {
// Do something
}
});
});
module.exports = router;
I was wondering: how can I make the mysql or the connectionpool visible in the entire application? I don't want to redeclare them on each route file I'll create. I'm looking something like an include or require method.
Any idea?
Create a separate module to act as an interface to retrieving SQL connections like so:
var mysql = require('mysql');
var connectionpool = mysql.createPool({
host : 'localhost',
user : 'user',
password : 'pass',
database : 'database'
});
exports.getConnection = function (callback) {
connectionpool.getConnection(callback);
};
Then in another file:
var connections = require('./connections');
connections.getConnection(function (err, c) {
// Use c as a connection
c.query("select * from table limit 10 ",function(err,rows){
//this is important release part
c.release();
if(!err) {
console.log(rows);
}
});
});
I'm building a node.js app that is a REST api using express and mongoose for my mongodb. I've got the CRUD endpoints all setup now, but I was just wondering two things.
How do I expand on this way of routes, specifically, how do I share modules between routes. I want each of my routes to go in a new file, but obviously only one database connection as you can see i've included mongoose at the top of people.js.
Do I have to write out the schema of the model 3 times in my people.js? The first schema defines the model, then I list all the vars out in the createPerson and updatePerson functions. This feels like how I made php/mysql CRUD back in the day lol. For the update function, I've tried writing a loop to loop through "p" to auto detect what fields to update, but to no avail. Any tips or suggestions would be great.
Also, I'd love any opinions on the app as a whole, being new to node, it's hard to know that the way you are doing something is the most efficient or "best" practice. Thanks!
app.js
// Node Modules
var express = require('express');
app = express();
app.port = 3000;
// Routes
var people = require('./routes/people');
/*
var locations = require('./routes/locations');
var menus = require('./routes/menus');
var products = require('./routes/products');
*/
// Node Configure
app.configure(function(){
app.use(express.bodyParser());
app.use(app.router);
});
// Start the server on port 3000
app.listen(app.port);
/*********
ENDPOINTS
*********/
// People
app.get('/people', people.allPeople); // Return all people
app.post('/people', people.createPerson); // Create A Person
app.get('/people/:id', people.personById); // Return person by id
app.put('/people/:id', people.updatePerson); // Update a person by id
app.delete('/people/:id', people.deletePerson); // Delete a person by id
console.log('Server started on port ' + app.port);
people.js
//Database
var mongoose = require("mongoose");
mongoose.connect('mongodb://Shans-MacBook-Pro.local/lantern/');
// Schema
var Schema = mongoose.Schema;
var Person = new Schema({
first_name: String,
last_name: String,
address: {
unit: Number,
address: String,
zipcode: String,
city: String,
region: String,
country: String
},
image: String,
job_title: String,
created_at: { type: Date, default: Date.now },
active_until: { type: Date, default: null },
hourly_wage: Number,
store_id: Number, // Inheirit store info
employee_number: Number
});
var PersonModel = mongoose.model('Person', Person);
// Return all people
exports.allPeople = function(req, res){
return PersonModel.find(function (err, person) {
if (!err) {
return res.send(person);
} else {
return res.send(err);
}
});
}
// Create A Person
exports.createPerson = function(req, res){
var person = new PersonModel({
first_name: req.body.first_name,
last_name: req.body.last_name,
address: {
unit: req.body.address.unit,
address: req.body.address.address,
zipcode: req.body.address.zipcode,
city: req.body.address.city,
region: req.body.address.region,
country: req.body.address.country
},
image: req.body.image,
job_title: req.body.job_title,
hourly_wage: req.body.hourly_wage,
store_id: req.body.location,
employee_number: req.body.employee_number
});
person.save(function (err) {
if (!err) {
return res.send(person);
} else {
console.log(err);
return res.send(404, { error: "Person was not created." });
}
});
return res.send(person);
}
// Return person by id
exports.personById = function (req, res){
return PersonModel.findById(req.params.id, function (err, person) {
if (!err) {
return res.send(person);
} else {
console.log(err);
return res.send(404, { error: "That person doesn't exist." });
}
});
}
// Delete a person by id
exports.deletePerson = function (req, res){
return PersonModel.findById(req.params.id, function (err, person) {
return person.remove(function (err) {
if (!err) {
return res.send(person.id + " deleted");
} else {
console.log(err);
return res.send(404, { error: "Person was not deleted." });
}
});
});
}
// Update a person by id
exports.updatePerson = function(req, res){
return PersonModel.findById(req.params.id, function(err, p){
if(!p){
return res.send(err)
} else {
p.first_name = req.body.first_name;
p.last_name = req.body.last_name;
p.address.unit = req.body.address.unit;
p.address.address = req.body.address.address;
p.address.zipcode = req.body.address.zipcode;
p.address.city = req.body.address.city;
p.address.region = req.body.address.region;
p.address.country = req.body.address.country;
p.image = req.body.image;
p.job_title = req.body.job_title;
p.hourly_wage = req.body.hourly_wage;
p.store_id = req.body.location;
p.employee_number = req.body.employee_number;
p.save(function(err){
if(!err){
return res.send(p);
} else {
console.log(err);
return res.send(404, { error: "Person was not updated." });
}
});
}
});
}
I have taken another approach here. Not saying it is the best, but let me explain.
Each schema (and model) is in its own file (module)
Each group of routes for a particular REST resource are in their own file (module)
Each route module just requires the Mongoose model it needs (only 1)
The main file (application entry point) just requires all route modules to register them.
The Mongo connection is in the root file and is passed as parameter to whatever needs it.
I have two subfolders under my app root - routes and schemas.
The benefits of this approach are:
You only write the schema once.
You do not pollute your main app file with route registrations for 4-5 routes per REST resource (CRUD)
You only define the DB connection once
Here is how a particular schema file looks:
File: /schemas/theaterSchema.js
module.exports = function(db) {
return db.model('Theater', TheaterSchema());
}
function TheaterSchema () {
var Schema = require('mongoose').Schema;
return new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
address: { type: String, required: true },
latitude: { type: Number, required: false },
longitude: { type: Number, required: false },
phone: { type: String, required: false }
});
}
Here is how a collection of routes for a particular resource looks:
File: /routes/theaters.js
module.exports = function (app, options) {
var mongoose = options.mongoose;
var Schema = options.mongoose.Schema;
var db = options.db;
var TheaterModel = require('../schemas/theaterSchema')(db);
app.get('/api/theaters', function (req, res) {
var qSkip = req.query.skip;
var qTake = req.query.take;
var qSort = req.query.sort;
var qFilter = req.query.filter;
return TheaterModel.find().sort(qSort).skip(qSkip).limit(qTake)
.exec(function (err, theaters) {
// more code
});
});
app.post('/api/theaters', function (req, res) {
var theater;
theater.save(function (err) {
// more code
});
return res.send(theater);
});
app.get('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
// more code
});
});
app.put('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
// more code
});
});
app.delete('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
return theater.remove(function (err) {
// more code
});
});
});
};
And here is the root application file, which initialized the connection and registers all routes:
File: app.js
var application_root = __dirname,
express = require('express'),
path = require('path'),
mongoose = require('mongoose'),
http = require('http');
var app = express();
var dbProduction = mongoose.createConnection('mongodb://here_insert_the_mongo_connection_string');
app.configure(function () {
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(application_root, "public")));
app.use('/images/tmb', express.static(path.join(application_root, "images/tmb")));
app.use('/images/plays', express.static(path.join(application_root, "images/plays")));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.get('/api', function (req, res) {
res.send('API is running');
});
var theatersApi = require('./routes/theaters')(app, { 'mongoose': mongoose, 'db': dbProduction });
// more code
app.listen(4242);
Hope this was helpful.
I found this StackOverflow post very helpful:
File Structure of Mongoose & NodeJS Project
The trick is to put your schema into models directory. Then, in any route, you can require('../models').whatever.
Also, I generally start the mongoose db connection in app.js, and only start the Express server once the connection is up:
mongoose.connect('mongodb://localhost/whateverdb')
mongoose.connection.on('error', function(err) {
console.log("Error while connecting to MongoDB: " + err);
process.exit();
});
mongoose.connection.on('connected', function(err) {
console.log('mongoose is now connected');
// start app here
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
});
I'd take a look at this project https://github.com/madhums/node-express-mongoose-demo . It is a great example on how to build a nodejs application in a standard way.