Using sails.js with an existing postgres database - node.js

I was looking at using Sails for an app that we are developing.
I'm using the sails-postgresql adapter which uses the waterline orm.
I have an existing database that I want to connect to.
If I create a model using generate something
and then in my model I have
attributes:{
title:{type:'String'}
}
If I browse to localhost/something the orm deletes all the columns in the something table except title.
Is there a way to stop it from doing this? This app should not delete columns on this database.
Thanks!

I am the author of Sails-Postgresql. Sails has an ORM called Waterline that it uses for managing data. The default setting assumes that you would want to auto-migrate your database to match your model attributes. Because Postgresql is a SQL database the Sails-Postgresql adapter has a setting called syncable that defaults to true. This would be false in a NoSQL database like redis.
This is easy to turn off if you want to manage your database columns yourself. You can add migrate: safe to your model and it won't try and update your database schema when you start Sails.
module.exports = {
adapter: 'postgresql',
migrate: 'safe',
attributes: {
title: { type: 'string' }
}
};
Sails doesn't have anything like migrations in Rails. It uses auto-migrations to attempt to remove this from your development process and then leaves updating your production schema to you.

Related

Create MySql schema in the model in express application

I am using express-MVC-generator for creating app skeleton in node js and once I have my project structured, I need to change default database in mongo for a MySQL database but I canĀ“t find how to create a MySQL schema from database in the model file. Is there a way to do that?
After research over the web, I found that the best option to solve my problem is to use sequelize, sequelize-cli to generate the models from an existing database.
https://www.npmjs.com/package/sequelize-cli

node express postgres - why and how to connect to database using pg module?

I am super new to node express and postgres and wondering the following:
const pg=require('pg').native
const client=new pg.Clirnt('postgres ...')
what is const?
pg is used to create a client to connect to the Postgres database-correct?
If so
var db = new Sequelize('postgres://localhost:5432/mydb')
would work too or would I just have created a database without connecting it?
Why exactly do I need to connect at all-to do what?
Thanks a lot!
const is constant in javascript which was introduced in ES6 specification.
node-postgres is a client for PostgreSQL.
Sequelize is using node-postgres for working with PostgreSQL database, so yes, in the nutshell, it will act like node-postgres.
Imagine the warehouse, that's your database, where you have different shelves, that's your tables, to take or put different items into warehouse you need workers that will do your instructions like - INSERT someitem INTO items_shelf;. So worker is the client like Sequelize or node-postgres. The important part, warehouse should be open, otherwise, workers couldn't access to it, so your database should be turned on.
Hope I'm explained understandable enough.
what is const?
TLDR; variables that can't be re-assigned. scoped the same way as var. Part of es6.
pg is used to create a client to connect to the postgres database?
yes, note you need to do npm install --save pg as well as npm install --save sequelize. the save flag adds the packages to the package.json file for your convenience.
would I just have created a database without connecting it?
That bit of code should instantiate a connector - you haven't modified the database, and you also don't really know if the connection works yet.
why exactly do I need to connect at all?
The pg library looks to use a connection pool; this means you set it up once, and then you use it repeatedly as desired and it handles the connections for you. You connect now so you can run queries against the database later.
This snippet of code connects to a postgres instance running locally on my machine, and tests that it can connect - per the docs
const Sequelize = require('sequelize');
var sequelize = new Sequelize('postgres://localhost:5432/postgres');
sequelize.authenticate().then(() => {
console.log('yay');
}).catch((e) => {
console.log('nooo', e);
});

Multiple db connections in sails.js with migration setting per connection

I'm using two connections in sails app: mongodb and postgresql. For mongodb i want to use "alter" strategy, but postgres db must be readonly. Is there any way to achieve this?
You cannot define it at the connection level, but you can override the configuration for the models of your choice.
// in api/models/PosgresModel.js
module.exports = {
migrate: 'safe',
attributes: {
// The attributes definitions
}
}

How to deal with calling sequelize.sync() first?

I'm a bit new to developing in nodejs, so this is probably a simple problem. I'm building a typical webapp based on express + sequelize. I'm using sqlite in-memory since I'm just prototyping at the moment. I understand if I were to use a persistent sqlite file, this may not be a problem, but that's not my goal at the moment. Consider the following:
var User = sequelize.define("User", {
"username": DataTypes.STRING,
// etc, etc, etc
});
sequelize.sync();
User.build({
"username": "mykospark"
});
At first, I got an error on User.build() about the Users table not existing yet. I realized that sequelize.sync() was being called async, and the insert was happening before the table was created. I then re-arranged my code so that the User.build() call was inside of sequelize.sync().complete() which fixes the problem, but I'm not sure how to apply this to the rest of my project.
My project uses models in a bunch of different places. It is my understanding that I just want to call sequelize.sync() once after my models are defined, then they can be used freely. I could probably find some way to block the entire nodejs app until sequelize.sync() finishes, but that doesn't seem like good form. I suppose I could wrap every single model operation into a sequelize.sync().complete() call, but that doesn't seem right either.
So how do people usually deal with this?
Your .sync() call should be called once within your app.js file. However, you might have additional calls if you manage multiple databases in one server. Typically your .sync() call will be in your server file and the var User = sequelize.define("ModelName"... will be in your models/modelName.js file. Sequelize suggests this type of guidance to "create a maintainable application where the database logic is collected in the models folder". This will help you as your development grows. Later in the answer, I'll provide an easy step to follow for initializing the file structure.
So for your case, you would have app.js, models/index.js and models/users.js. Where app.js would be your server running the .sync() method. In the models folder you will have the required index.js folder where you configure a connection to the database and collect all the model definitions. Finally you have your user.js files where you add your model with class and instance methods. Below is an example of the models/user.js file you might find helpful.
user.js
module.exports = function(sequelize, DataTypes) {
return sequelize.define('User', {
username: DataTypes.STRING,
},{
classMethods: {
doSomething: function(successcb, errcb, request) {}
},
instanceMethods: {
someThingElse: function(successcb, errcb, request) {}
}
});
};
models/index.js --> See here
EDIT 03/14/17
Now the best option to setup your node app with sequelize is to use sequelize-cli. This is sequelize migrations and has very useful functionality in development and production environments. For the scope of this question and revision to the answer, the best approach is the following:
npm install sequelize-cli
Use npm install sequelize-cli -g if you want it installed globally.
Then initialize sequelize migrations:
sequelize init
It should install the following folders and files structure in the folder you initiated the command:
config:
-config.json
models:
-index.js
seeders:
migrations:
If you want to create a model you can run the following command and it will auto generate the file structure for you. Here is an example
sequelize model:create --name User --attributes "user:string email:string"
Next you should be able to see the new model page in models/page.js.
config:
-config.json
models:
-index.js
-user.js
-page.js
seeders:
migrations:
You'll need to then go into you models/index.js and define your new model for your database to access the correct path for that model. Here is an example:
models/index.js
var sq = new Sequelize(dbname, user, password, config);
db = {
Sequelize: Sequelize,
sequelize: sq,
page: sq.import(__dirname + '/page.js'),
user: sq.import(__dirname + '/user.js')
}
module.exports = db;
If you need to make changes to the model you can go into the migrations folder and add methods. Follow the sequelize migration docs here. Now, about the app.js server. Before you run your server you need to initialize your databases. I use the following script to initialize the database before running the server to setup a postgres db:
postgresInit.sh
[...]
`sudo -u postgres createdb -U postgres -O $PG_USER $PG_DB. `
If you prefer a javascript solution, there is an SO solution here
app.js
[...]
console.log('this will sync your table to your database')
console.log('and the console should read out Executing (default): CREATE TABLE IF NOT EXISTS "TABLE NAME"....')
db.sequelize.sync(function(err){});

Abstract layer for Node.js database

I have been looking around for simple database abstraction implementation, then i found great article http://howtonode.org/express-mongodb, which old but I still like the idea.
Well maybe the construction, could take some kind of object literal with database settings.
So the main idea is that there could be different implementations of UserService-s, but locate in different directories and require only the one that's needed.
/data-layer/mongodb/user-service.js
/post-service.js
/comment-service.js
/data-layer/couchdb/user-service.js
/post-service.js
/comment-service.js
When the Database is needed, I wil get it with var UserService = require(__dirname + '/data-layer/mongodb/user-service).UserService(db); where var db = "open db object"
Would this be the correct way to do it or is there any better solutions ?
There are a few solutions, available via NPM :
Node-DBI : "Node-DBI is a SQL database abstraction layer library, strongly inspired by the PHP Zend Framework Zend_Db API. It provides unified functions to work with multiple database engines, through Adapters classes. At this time, supported engines are mysql, mysql-libmysqlclient and sqlite3". Looks like the developpment has been paused.
Accessor : "A database wrapper, provide easy access to databases." Supports only MySQL and MongoDB at the moment.
Activerecord : "An ORM written in Coffeescript that supports multiple database systems (SQL, NoSQL, and even REST), as well as ID generation middleware. It is fully extendable to add new database systems and plugins."
Update:
Since I've posted this answer, I have abandoned mongoose for official MongoDB NodeJS Drivers as it is fairely intuitive and more loyal to the concept of NoSQL databases.
Original Answer:
I though it might be time to update the answer of an old question:
If you want to use MongoDB as your document-oriented database, mongoose is a good choice and easy to use (example from official site):
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var Cat = mongoose.model('Cat', { name: String });
var kitty = new Cat({ name: 'Zildjian' });
kitty.save(function (err) {
if (err) // ...
console.log('meow');
});
For a rather modern approach, Mongorito is a good ODM which uses ES6 generators instead of callbacks.
As of 06.2015 I reckon that the best ORM for SQL databases with Node.js/io.js is Sequelize supporting the following databases:
PostgreSQL
MySQL
MariaDB
SQLite
MSSQL
The setup is fairly easy:
var sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql'
});
// Or you can simply use a connection uri
var sequelize = new Sequelize('postgres://user:pass#example.com:5432/dbname');
It also provides transactions, migrations and many other goodies.

Resources