Cannot Read Property 'use_env_variable' of Undefined Sequelize

Using PostgreSQL and Sequelize to persist our information

It's been quite a journey since the part i of this serial, In this tutorial, we will persist our information with a database using Postgres and Sequelize. Sequelize is an ORM for Nodejs, it supports PostgreSQL, MySQL, SQLite and MSSQL. the source lawmaking for this tutorial can exist establish here

Configure Sequelize

To get started we'll get-go by installing some dependencies. First, nosotros'll install`, sequelize-cli creates a command line interface for us to run Sequelize related commands in our app.

          $ npm install -salve sequelize-cli        

To configure Sequelize for our projection we are going to create a .sequelizerc file in the root of our app

          $ impact .sequelizerc        

inside the file type the post-obit

          const path = require('path');

module.exports = {
"config": path.resolve('./config', 'config.json'),
"

models-path ": path.resolve('./models'),
" migrations-path ": path.resolve('./migrations')
};

The sequelizerc file is going to bootstrap our application with the above paths, the file is going to incorporate the configuration for our application, the models path volition contain our application models, will comprise the different migrations for our application. the migration files are used to create our app's tabular array using the models that we create. the models contain the design for our application tables

The next thing to do is to install Sequelize and another dependencies,

          $ npm install --save sequelize pg pg-hstore        

is a PostgreSQL client for Node.js, pg is responsible for creating our application'south database connectedness. is a node parcel for serializing and deserializing JSON data to hstore format. read more about pg-hstore here.

Adjacent run

          $ sequelize init        

this is going to bootstrap our application with the path specified in file. After running information technology you should have a config folder which contains a file, a model folder which contains some configurations for the models and a migration folder.

let's go through the index.js file in the models folder, some required node modules were imported, the line with checks if whatsoever environment variable is prepare, if it is set then nosotros use the settings for that environment variable otherwise we use the alternative settings provided for that surroundings. the process.env gives admission to the node env, but this will non piece of work unless we have a dotenv package installed, this volition give u.s. access to the node surround from our application.

Configure dotenv

          $ npm install --save dotenv        

afterward installation, require the dotenv file as early as possible in your application. I'll require mine at the superlative of file in the models folder

          require('dotenv').config()        

we required the dotenv module and call the method config on it. the next thing we need to do is to create file, this volition contain all our node environment variables. At the root of your app create a file

          $ touch .env        

now to prepare Postgres for our application we can either use the settings provided in the config.json file, we'll only supplant the required information with the information we Setup when nosotros installed Postgres or we can use an surroundings variable. in the development section, delete everything there and supervene upon it with this

          "development": {                      "use_env_variable": "DATABASE_URL"
},

now our model configuration is going to make use of this surroundings variable when we are on development. think nosotros had something like this in our model:

          if (config.use_env_variable) {
var sequelize = new
Sequelize(process.env[config.use_env_variable], config);
} else { var sequelize = new Sequelize(config.database, config.username,
config.countersign, config);
}

so nosotros are checking if our config is set up, in this case, our config variable is set to development object, this line of lawmaking is doing that.

          var env       = process.env.NODE_ENV || 'development';          var config    = require(__dirname + '/../config/config.json')[env];        

we prepare the env to development by default, then we required the config.json file and pull out the development surroundings. so variable is equal to our development object set up in file. and then we then check if is ready, if it is we use which translates to to get the value set in that environment. but we don't take ` fix in our node environment. to exercise that nosotros volition go to our file and set it, so the .env file is where we gear up custom node_env we want to have access to in our code. in your .env file type the following:

          DATABASE_URL=postgres://username:countersign@localhost:5432/database_name        

If you don't have a countersign setup and so your configuration should be in this format:

          DATABASE_URL=postgres://username@localhost:5432/database_name        

and so our models will brand use of this to set up our database, replace username with your Postgres username, mine is , replace password with your password and database_name with the name of your database. so in my case, we'll accept something like this:

          DATABASE_URL=postgres://postgres:mypassword@localhost:5432/todo-app        

then create your Postgres database from your concluding like this:

          $ createdb todoapp        

ensure you accept Postgres installed otherwise this will not piece of work.

note that anything we set up in our .env file is available in our node environment and can be accessed with in our case `. is equal to whatever we set it to be. we could fix it to development, production or testing, depending on what environment nosotros want to work on. we could fix information technology in the .env file also. In our case, if it is not set we just default to evolution: .

Creating our models

Now that we have our configurations out of the fashion, the next thing is to create our models, Each todo is going to have todo items, so a todo can have many items under it, so we can then say that the relationship between a todo and the todo item is a ane to many human relationship. Now to create this relationship we showtime have to create our models, run the following control to create our models

Todo models

          $             node_modules/.bin/sequelize             model:create --name Todo --attributes title:string        
  • — name refers to the name of the model
  • — attribute refers to the attributes the model should have

this will generate a todo.js file in our model and the todo model should look something like this:

          'utilize strict';          module.exports = (sequelize, DataTypes) => {                      var Todo = sequelize.define('Todo', {                      title: DataTypes.STRING          }, {});          Todo.associate = function(models) {          //              associations can be defined here                    };          return Todo;          };        

A migration file volition also be automatically generated in the migration folder and information technology should wait similar this:

          'use strict';          module.exports = {          upward: (queryInterface, Sequelize) => {          return queryInterface.createTable('Todos', {          id: {          allowNull: false,          autoIncrement: true,          primaryKey: true,          type: Sequelize.INTEGER          },          title: {                      type: Sequelize.Cord          },          createdAt: {                      allowNull: imitation,                      type: Sequelize.Engagement          },          updatedAt: {                      allowNull: imitation,                      type: Sequelize.Engagement          }          });          },          down: (queryInterface, Sequelize) => {          return queryInterface.dropTable('Todos');          }          };        

TodoItem

We'll do the aforementioned thing for todo items, run the post-obit command in your terminal

          $ node_modules/.bin/sequelize model:create --proper name TodoItem --attributes description:string        

the todoItem model should wait something like this:

          'apply strict';          module.exports = (sequelize, DataTypes) => {                      var TodoItem = sequelize.ascertain('TodoItem', {                      clarification: DataTypes.STRING                      }, {});          TodoItem.associate = function(models) {          //              associations can be defined hither                    };          render TodoItem;          };        

the migration file

          'use strict';          module.exports = {          upward: (queryInterface, Sequelize) => {          return queryInterface.createTable('TodoItems', {          id: {                      allowNull: imitation,                      autoIncrement: true,                      primaryKey: true,                      type: Sequelize.INTEGER          },          clarification: {                      type: Sequelize.Cord          },          createdAt: {                      allowNull: faux,                      blazon: Sequelize.DATE          },          updatedAt: {                      allowNull: false,                      type: Sequelize.DATE          }          });          },          down: (queryInterface, Sequelize) => {          return queryInterface.dropTable('TodoItems');          }          };        

Refactoring

nosotros are going to refactor some part of our code to make use of Es6, change the functions to arrow functions and all vars to const

          module.exports = (sequelize, DataTypes) => {          const Todo = sequelize.define('Todo', {          championship: {          type: DataTypes.STRING,          allowNull: false,          },          });          Todo.associate = (models) => {          //              associations can be defined hither                    Todo.hasMany(models.TodoItem, {          foreignKey: 'todoId',          });          };          return Todo;          };        

in the higher up code we modified our todo.js file, first we included an extra aspect to the championship field what this attribute does is that it made the title field not nullable, significant that the database is going to throw an error if we try to add an empty or null value to the championship field, the DataTypes.string means that we simply expect a string value in this field, anything other than that the database is going to throw an fault

Also, we created a human relationship between out Todo and TodoItem, similar nosotros said before, every single Todo has many todoItem, that relationship is divers with the hasMany many method of the Todo Model. The foreignKey: 'todoId', means that todoId is going to be the strange fundamental cavalcade in todoItem, you can read more than most foreign keys here.

we will as well make the same modification to ur TodoItem

          module.exports = (sequelize, DataTypes) => {          const TodoItem = sequelize.ascertain('TodoItem', {          description: {          blazon: DataTypes.String,          allowNull: false,          },          });          TodoItem.acquaintance = (models) => {          //              associations tin can be divers hither                    TodoItem.belongsTo(models.Todo, {          foreignKey: 'todoId',          onDelete: 'Cascade',          });          };          return TodoItem;          };        

Every unmarried Todo has many TodoItems and each TodoItem belongs to one Todo, that is why we have the TodoItem.belongsTo define in our model above. The onDelete: 'Cascade' means if we delete a todo and so the associated todoITem should as well be deleted

Now that we accept our models ready we tin now run our migrations, in the migration folder we'll have a ready of migration files, The files contain scripts for creating and dropping our database tables, the migration scripts were created to model what we defined in our models, again, the scripts are responsible for creating and dropping our tables every time we run it. The up part is responsible for creating our tables and its columns, the down function is responsible for undoing what the up function runs.

we are going to exist modifying our migration scripts since we modified our model files, this is to ensure consistency between our model and migrations

since we are going to be having a foreingkey: todoId in the TodoItem as we defined in our models, we are going to change the migration script for TodoItem to include a todoId

we are going to include this in the migration file for TodoItem

          todoId: {
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
references: {
model: 'Todos',
fundamental: 'id',
every bit: 'todoId',
},
},

the references contains a belongings called model, this tells us the model this ForeignKey refers to, in our case information technology is the Todos, the adjacent attribute is the key attribute which tells us what the todoId in todoItems maps to in Todos models, in this example it is the id of the Todos table, what this means is that the id of the todo table is the same as the todoId in the TodoItem table

the new migrations file should wait something like this:

          module.exports = {          upwardly: (queryInterface, Sequelize) => {          render queryInterface.createTable('TodoItems', {          id: {          allowNull: false,          autoIncrement: true,          primaryKey: true,          type: Sequelize.INTEGER          },          description: {          type: Sequelize.String          },          createdAt: {          allowNull: false,          blazon: Sequelize.Appointment          },          updatedAt: {          allowNull: faux,          type: Sequelize.Engagement          },          todoId: {          type: Sequelize.INTEGER,          onDelete: 'Cascade',          references: {          model: 'Todos',          key: 'id',          every bit: 'todoId',          },          },          });          },          down: (queryInterface, Sequelize) => {          return queryInterface.dropTable('TodoItems');          }          };        

Now we are fix to run our migration, running migrations we run the script in the migrations files and create our tables. Before running the migrations, on your last export your database url like this:

          consign DATABASE_URL=postgres://postgres@localhost:5432/database_name        

Run the migration like this:

          node_modules/.bin/sequelize db:migrate        

you should encounter something like this run in your terminal

          == 20180908120703-create-todo: migrating =======
== 20180908120703-create-todo: migrated (0.025s)
== 20180908121020-create-todo-detail: migrating =======
== 20180908121020-create-todo-item: migrated (0.013s)

If you check your database you volition see that your table has been created and the relationship has been defined

Now information technology is time to persist our information, to interact with the database we created nosotros are going to be using the models we created, with the models we have access to enormous methods we can use to interact with our database, we tin perform Grime operations through this methods,

In the controller of our todo app i.e import the model

          import models from '../models';        

This will get to the and import exported at the lesser of the file. through this model, we can interact with the database.

Create Todo

Now let'due south modify method, the method to create todo currently looks like this

          createTodo(req, res) {          if (!req.torso.title) {                      return res.status(400).send({                      success: 'simulated',                      message: 'title is required',          });          } else if (!req.trunk.clarification) {                      return res.status(400).transport({                      success: 'imitation',                      message: 'description is required',                    });          }          const todo = {                      id: db.length + ane,                      title: req.body.title,                      clarification: req.torso.description,          };          db.push button(todo);          render res.status(201).send({                      success: 'true',                      message: 'todo added successfully',                      todo,          });          }        

Now instead of using to push a new todo to our we are going to make use of the create method provided past our models, as well we'll remove the description field since the todos tabel does not take a field for description, the description will be added in the todoItem table

Now our createTodo method looks like this:

          createTodo(req, res) {                      if (!req.body.title) {                      return res.condition(400).ship({                      success: 'false',                      message: 'championship is required',                      });          }          const todo = {                      title: req.body.championship,          };          models.Todo.create(todo).then((todo) => {                      return res.condition(201).send({                      success: 'true',                      bulletin: 'todo added successfully',                      todo,                      });          });          }        

The function runs when the todo has been successfully added to the database, the parameter passed into the function in the is the todo response from the database after the create functioning is completed, so what we are basically proverb in a layman language is that the line of lawmaking should create a todo in the database, and because a database interaction will take a few milliseconds to complete nosotros don't desire to wait for that operation to end before nosotros move to the next line of code, so we go along to the next line of code but when that database performance finish executing the code in the should run with the returned consequence which we passed as a parameter called to the function. This whole functioning is called Promises in javascript, you can study more than on promises here.

Our returned response looks similar this:

Now we have a problem, we can create another todo with the same title and it will be added to the database, we need a fashion to ensure that a todo with same title doesn't get added to the database. To do this we have to starting time check if the todo we are trying to add together to the database exists already, if it does then we render a bulletin to the user, if it doesn't exist already then we add it to the database. so we have to search the database for the title that the user provide to united states of america, if the title exists already so we will render a message to the user, otherwise, nosotros'll add the todo top the database

Later on implementing this our createTodo should now look like this

          createTodo (req, res) {                      if (!req.torso.championship) {                      return res.status(400).transport({                      success: 'false',                      message: 'title is required',                      });                      }                      models.Todo.findOne({                      where: { championship: req.body.championship }                      })                      .and so((todoFound) => {                      if (todoFound) {                      render res.status(403).send({                      success: 'true',                      bulletin: 'A todo with that championship exist already',                                });                      }                      const todo = {                      title: req.trunk.title,                      };                      models.Todo.create(todo).then((todo) => {                      return res.status(201).send({                                success: 'truthful',                      bulletin: 'todo added successfully',                      todo,                      });                                });                      })          }        

Now we are using the method to check if a todo with the championship provided already exist, if information technology does the we return a message, otherwise we get ahead to add the todo.

Attempting to add a Todo that already exist our response looks similar this

Go All Todos

Now let's modify our method, the lawmaking currently looks similar this

          getAllTodos(req, res) {                      return res.status(200).send({                      success: 'true',                      message: 'todos retrieved successfully',                      todos: db,                      });          }        

Now we need to make utilise of the method provided past our models to observe all todos

the modification looks like this:

          getAllTodos(req, res) {                      models.Todo.findAll()                      .then(todos => res.status(200).transport({                      success: 'truthful',                      bulletin: 'todos retrieved successfully',                      todos,                      }));          }        

the response looks similar this:

Become a unmarried Todo

the old code for get a single todo

          getTodo(req, res) {                      const id = parseInt(req.params.id, x);                      db.map((todo) => {                      if (todo.id === id) {                      return res.status(200).send({                      success: 'true',                      message: 'todo retrieved successfully',                      todo,                                });                                }                      });                      return res.status(404).send({                      success: 'false',                      message: 'todo does not exist',                      });          }        

The new code looks like this:

          getTodo(req, res) {                      const id = parseInt(req.params.id, ten);                      models.Todo.findById(id)                      .so((todo) => {                      if (todo) {                      render res.status(200).transport({                      success: 'true',                      message: 'todo retrieved successfully',                      todo,                      });                      }                      return res.status(404).transport({                      success: 'false',                      message: 'todo does not exist',                      });                      });          }        

We utilise the method and pass the Id of the todo we wish to get, if the todo exist then we get a response and if the todo does not exist we get a response telling us that the todo does not exist

Note: If you lot are using sequelize v5, findById was replaced by findByPk

Todo that does not exist in the database

Decision

This marks the finish of this tutorial, as practised and before the next part of this serial you can change the endpoint for update and delete to make employ of our models, Also we'll not be working with the todoItem model we created, y'all can take that up as a challenge and add description to the todos that nosotros already created. Cheers!!

refrence

hendricksditach.blogspot.com

Source: https://medium.com/@haybams/using-postgresql-and-sequelize-to-persist-our-data-c86854a3c6ac

0 Response to "Cannot Read Property 'use_env_variable' of Undefined Sequelize"

Publicar un comentario

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel