DEV Community

Gurkirat Singh
Gurkirat Singh

Posted on

Pocket Guide on Sequelize ORM for NodeJS

Course Outline

Prerequisite Knowledge

  • Basics of nodejs

What will be covered in this course

In this course, you will learn how to make the data-driven application in nodejs using SQL database. And moreover, you will learn how to deal will database in using ORMs

Requirements

  • nodejs runtime
  • npm / yarn
  • any text editor
  • any sql server (we will be using MariaDB in this course)

Project

The project is in the project directory

NOTE: This course is made with jupyter notebook. If you want the notebook drop a message at tbhaxor@gmail.com. I will be adding more topics under misc, so make sure you subscribe to the repository.

Introduction to SQL

A database is an organized collection of data, generally stored and accessed electronically from a computer system. To communicate with this database there is standard language, known as SQL and abbv. for Structured Query Language.

Need of database

  • store data and make it easily accessible
  • persistent and fast retrieval
  • fault tolerance
  • need not to open gigantic set fo file to look for a piece of information

There are basically two types of database SQL and NoSQL

In the case of SQL

  • the data is organized in a table-like structure
  • provided linking of tables via relationships
  • for each table, there is fixed schema and it should be followed while adding a new entry
  • database consists of tables, tables consist of rows and columns, the entry is added in a row is often called a record
  • datatypes in SQL → https://mariadb.com/kb/en/data-types/

For example, creating a table named student in database school

CREATE TABLE school.students (
    student_id int,
    last_name varchar(255),
    first_name varchar(255),
    address varchar(255),
);
Enter fullscreen mode Exit fullscreen mode

This create table *** is a SQL query to create a table in the database (condition, the database should exist)

Now if you want to select all the records,

SELECT * FROM school.students;
Enter fullscreen mode Exit fullscreen mode

In the case of NoSQL

  • doesn't follow the approach that SQL follows
  • uses a different query language
  • database contains collections, collections contain documents. These documents are the records
  • document doesn't have to stick to the same schema
  • stores the data in binary JSON (called bson)
  • there are no relations, duplication of data is preferred

SQL vs NoSQL. What to choose and when

Horizontal scaling is simply adding more services to the existing app, providing more resources. Whereas vertical scaling is simply adding more resources to the same server.

Horizontal scaling is more challenging than vertical scaling

In the case of SQL

  • horizontal scaling is very difficult, but vertical scaling is easy
  • limitations of read/write queries per seconds
  • use this when you have multiple data, and you want data aggregation to be very easy

In the case of NoSQL

  • both horizontal and vertical scaling are easy
  • great performance for mass read/write operations
  • use this when you have to deal with big data

Note: It all depends what type of data you have

Setting up MariaDB

Installing MariaDB on Windows: Documentation | Video

Installing Mariadb on Linux: Documentation | Video

Connecting to the Server from NodeJS application

Installing the NodeJS package

# using yarn
yarn add mysql2

# using npm
npm i mysql2
Enter fullscreen mode Exit fullscreen mode
// requiring the packages
const mysql = require("mysql2");
Enter fullscreen mode Exit fullscreen mode

You can directly connect to the server using mysql.createConnection , but it will create only one connection that has to be closed after running the query. Opening and closing connections for every query doesn't seem to be a good approach for a larger applications. So you can create a pool of the connection to reuse the same

Read more about connection pooling: https://en.wikipedia.org/wiki/Connection_pool

const pool = mysql.createPool({
    host: "localhost",
    user: "root",
    database: "node_orm",
    password: "test@1234",
});

const connection = pool.promise();
Enter fullscreen mode Exit fullscreen mode
connection.execute(`CREATE  TABLE  products (
     id  INT NOT NULL AUTO_INCREMENT,
     title  VARCHAR(255) NOT NULL,
     price  DOUBLE UNSIGNED NOT NULL,
     description  VARCHAR(255) NOT NULL,
     PRIMARY KEY( id )
);`)
    .then(console.log)
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  ResultSetHeader {
    fieldCount: 0,
    affectedRows: 0,
    insertId: 0,
    info: '',
    serverStatus: 2,
    warningStatus: 0
  },
  undefined
]
Enter fullscreen mode Exit fullscreen mode

Running Basic CRUD Quering

Create

connection.execute(`INSERT INTO products (title, price, description) 
                    VALUES ('ORM in Nodejs', 499.99, 'A book on introduction on ORM in nodejs')`)
    .then(console.log)
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  ResultSetHeader {
    fieldCount: 0,
    affectedRows: 1,
    insertId: 1,
    info: '',
    serverStatus: 2,
    warningStatus: 0
  },
  undefined
]
Enter fullscreen mode Exit fullscreen mode

Read

// reading all the data
connection.execute(`SELECT * FROM products;`)
    .then(_ => console.log(_[0]))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  BinaryRow {
    id: 1,
    title: 'ORM in Nodejs',
    price: 499.99,
    description: 'A book on introduction on ORM in nodejs'
  }
]
Enter fullscreen mode Exit fullscreen mode
// reading a specific record
connection.execute(`SELECT * FROM products WHERE id=1;`)
    .then(_ => console.log(_[0]))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  BinaryRow {
    id: 1,
    title: 'ORM in Nodejs',
    price: 499.99,
    description: 'A book on introduction on ORM in nodejs'
  }
]
Enter fullscreen mode Exit fullscreen mode

Update

connection.execute(`UPDATE products SET title='[BOOK] ORM for Nodejs' WHERE id=1;`)
    .then(_ => console.log(_[0]))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
ResultSetHeader {
  fieldCount: 0,
  affectedRows: 1,
  insertId: 0,
  info: 'Rows matched: 1  Changed: 1  Warnings: 0',
  serverStatus: 2,
  warningStatus: 0,
  changedRows: 1
}
Enter fullscreen mode Exit fullscreen mode
// reading a specific record
connection.execute(`SELECT * FROM products WHERE id=1;`)
    .then(_ => console.log(_[0]))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  BinaryRow {
    id: 1,
    title: '[BOOK] ORM for Nodejs',
    price: 499.99,
    description: 'A book on introduction on ORM in nodejs'
  }
]
Enter fullscreen mode Exit fullscreen mode

Delete

connection.execute(`DELETE FROM products WHERE id=1;`)
    .then(_ => console.log(_[0]))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
ResultSetHeader {
  fieldCount: 0,
  affectedRows: 1,
  insertId: 0,
  info: '',
  serverStatus: 2,
  warningStatus: 0
}
Enter fullscreen mode Exit fullscreen mode
// reading a specific record
connection.execute(`SELECT * FROM products WHERE id=1;`)
    .then(_ => console.log(_[0]))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[]
Enter fullscreen mode Exit fullscreen mode

Introduction ORM

ORM stands for Object-Relational Mapping (ORM) is a programming technique for converting data between relational databases and object-oriented programming languages such as Java, C#, etc.

What does an ORM consist of

  1. An API to perform basic CRUD operations on objects of persistent classes.
  2. A configurable facility for specifying mapping metadata.
  3. A technique to interact with transactional objects to perform
    • dirty checking
    • lazy association fetching
    • other optimization functions
    • pre-execution validations

Why ORM? Why not executing raw queries

  1. Focus on business code rather than dealing with database
  2. Transaction management and automatic key generation.
  3. Community support of database security
  4. Encapsulation of SQL queries from OO logic.

The ORM for nodejs is Sequelize

Installing sequelize

# using yarn
yarn add sequelize

# using npm
npm i sequelize
Enter fullscreen mode Exit fullscreen mode

Also, you would have to install the drivers

# One of the following:
npm install --save pg pg-hstore # Postgres
npm install --save mysql2
npm install --save mariadb
npm install --save sqlite3
npm install --save tedious # Microsoft SQL Server
Enter fullscreen mode Exit fullscreen mode

NOTE: We will be using MariaDB

Connecting to Database

// importing the sequelize package
const { Sequelize, INTEGER, STRING, DOUBLE } = require("sequelize")
Enter fullscreen mode Exit fullscreen mode
const sequelize = new Sequelize("node_orm", "root", "test@1234", {
    dialect: "mariadb", // the database provider (here, mariadb)
    host: "localhost",
    logging: false
});
Enter fullscreen mode Exit fullscreen mode

Defining a Model

Models are the interface to the table in the database. It consists of the schema definition (which is often known as a model definition) and then you can run various method on the model to deal with the corresponding database and the table

// the first parameter is the name of the table
// the second parameter is the schema description
const Product = sequelize.define("products", {
    id: {
        type: INTEGER,
        autoIncrement: true,
        primaryKey: true
    },
    title: STRING(255),
    price: {
        type: DOUBLE,
        defaultValue: 0.0
    },
    description: STRING(255)
})
Enter fullscreen mode Exit fullscreen mode

Till now the model is in the memory. To synchronize the model with a database, you should use .sync() method

sequelize.sync({force: true})
    .then(()=> console.log("Table Created"))
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')
warning: please use IANA standard timezone format ('Etc/GMT0')
Table Created
Enter fullscreen mode Exit fullscreen mode

The table will look like the following

+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int(11)      | NO   | PRI | NULL    | auto_increment |
| title       | varchar(255) | YES  |     | NULL    |                |
| price       | double       | YES  |     | 0       |                |
| description | varchar(255) | YES  |     | NULL    |                |
| createdAt   | datetime     | NO   |     | NULL    |                |
| updatedAt   | datetime     | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+
Enter fullscreen mode Exit fullscreen mode

See how it created two more columns to maintain the track record of creation and updating. However, you can forbid sequelize to do so by using timestamps: false while defining the model

The SQL query that sequelize actually ran in the background is

 CREATE TABLE IF NOT EXISTS `products`
             (
                          `id`          INTEGER auto_increment ,
                          `title`       VARCHAR(255),
                          `price`       DOUBLE PRECISION DEFAULT 0,
                          `description` VARCHAR(255),
                          `createdat`   datetime NOT NULL,
                          `updatedat`   datetime NOT NULL,
                          PRIMARY KEY (`id`)
             )
             engine=innodb; 
Enter fullscreen mode Exit fullscreen mode

Creating a Record

Product.create({
    title: "ORM book for nodejs developer",
    description: "An all in one resource on data driven application development using sql and orm in nodejs",
    price: 100.99
})
    .then(() => console.log("Record created")).catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')
Record created
Enter fullscreen mode Exit fullscreen mode

Fetching all the Records

Product.findAll()
    .then(v => {
        v.forEach(_ => console.log(_.dataValues))
    })
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



{
  id: 1,
  title: 'ORM book for nodejs developer',
  price: 100.99,
  description: 'An all in one resource on data driven application development using sql and orm in nodejs',
  createdAt: 2020-03-31T07:36:16.000Z,
  updatedAt: 2020-03-31T07:36:16.000Z
}
Enter fullscreen mode Exit fullscreen mode

Getting records based on conditions

__ = Product.findAll({ where: { id: 1 }})
    .then(v => {
        console.log(v[0].dataValues)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



{
  id: 1,
  title: 'ORM book for nodejs developer',
  price: 100.99,
  description: 'An all in one resource on data driven application development using sql and orm in nodejs',
  createdAt: 2020-03-31T07:36:16.000Z,
  updatedAt: 2020-03-31T07:36:16.000Z
}
Enter fullscreen mode Exit fullscreen mode

Getting specific columns only

__ = Product.findAll({ attributes: ["title"] })
    .then(v=>{
        console.log(v[0].dataValues)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



{ title: 'ORM book for nodejs developer' }
Enter fullscreen mode Exit fullscreen mode

Finding by Primary Key and Getting Particular Column

Product.findByPk(1, { attributes:["title", "price"] })
    .then(v => {
        console.log(v.dataValues)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



{ title: 'ORM book for nodejs developer', price: 100.99 }
Enter fullscreen mode Exit fullscreen mode

Updating the Records

Product.update({ title: "Book on NodeJS ORM" }, { where: { id: 1 } })
    .then(console.log)
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



[ 1 ]
Enter fullscreen mode Exit fullscreen mode
Product.findByPk(1, { attributes:["title", "price"] })
    .then(v => {
        console.log(v.dataValues)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



{ title: 'Book on NodeJS ORM', price: 100.99 }
Enter fullscreen mode Exit fullscreen mode

Deleting the Records

Product.destroy({
    where: {
        id: 1
    }
})
    .then(console.log)
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



1
Enter fullscreen mode Exit fullscreen mode
Product.findByPk(1, { attributes:["title", "price"] })
    .then(v => {
        console.log(v)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



null
Enter fullscreen mode Exit fullscreen mode

The null means record doesn't found

Relationships with Sequelize

Before heading forward, create a user model

const User = sequelize.define("users", {
    id: {
        type: INTEGER,
        autoIncrement: true,
        primaryKey: true
    },
    name: STRING,
    email: STRING
})
Enter fullscreen mode Exit fullscreen mode
sequelize.sync()
    .then(() => {
        console.log("Created new table")
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



Created new table
Enter fullscreen mode Exit fullscreen mode

One-to-Many

Product.belongsTo(User, {
    contraints: true, // adding relation contraints
    onDelete: "CASCADE" // delete products when user is deleted
})
User.hasMany(Product)
Enter fullscreen mode Exit fullscreen mode
products
Enter fullscreen mode Exit fullscreen mode

NOTE : About belongsTo and hasMany has been answered here → https://softwareengineering.stackexchange.com/a/152774

Reflecting changes in DB

sequelize.sync({ force: true })
    .then(() => {
        console.log("Created tables with relations")
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



Created tables with relations
Enter fullscreen mode Exit fullscreen mode

Creating a dummy user

User.findByPk(1)
    .then(v => {
        if (v == null)
        {
            console.log("User not found. Creating it")
            User.create({
                name: "Dummy User",
                email: "dummy@user.com"
                })
                .then(() => {
                    console.log("User Created")
                })
                .catch(console.warn)
        }
        else
        {
            console.log("User found. Not creating a new one")
        }
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



User not found. Creating it
User Created
Enter fullscreen mode Exit fullscreen mode

Finding User → Creating Product → Linking user with Product

User.findByPk(1)
    .then(v => {
        Product.create({
            title: "Product #1",
            description: "Sample description for Product #1",
            price: 10.99,
            userId: v.dataValues.id
        })
            .then(v => {
                console.log("New product created")
            })
            .catch(console.warn)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



New product created
Enter fullscreen mode Exit fullscreen mode

NOTE : fter fetching the user, you can use createProduct() for the particular user.

User.findByPk(1)
    .then(v => {
        v.createProduct({
            title: "Product #2",
            description: "Sample description for Product #2",
            price: 12.88,
        })
            .then(() => {
                console.log("Created product");
            })
            .catch(console.warn)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



Created product
Enter fullscreen mode Exit fullscreen mode

Getting products with user details

Product.findAll({ 
    include: [{
        model: User
    }]
})
    .then(v => {
        v.forEach(_ => {
            console.log(`Product ID: ${_.dataValues.id}`);
            console.log(`Product Title: ${_.dataValues.title}`);
            console.log(`Product Price: ${_.dataValues.price}`);
            console.log(`Added By: ${_.dataValues.user.name} (${_.dataValues.user.email})`);
            console.log("-------------------");
        })
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



Product ID: 1
Product Title: Product #1
Product Price: 10.99
Added By: Dummy User (dummy@user.com)
-------------------
Product ID: 2
Product Title: Product #2
Product Price: 12.88
Added By: Dummy User (dummy@user.com)
-------------------
Enter fullscreen mode Exit fullscreen mode

NOTE : To get products of particular user, use getProducts() method on that user object

Many-to-Many relationships

Create a new table, named cart

const Cart = sequelize.define("carts", {
    id: {
        type: INTEGER,
        autoIncrement: true,
        primaryKey: true
    }
});
Enter fullscreen mode Exit fullscreen mode
const CartItem = sequelize.define("cart_items", {
    id: {
        type: INTEGER,
        autoIncrement: true,
        primaryKey: true
    },
    quantity: INTEGER
})
Enter fullscreen mode Exit fullscreen mode
Cart.belongsTo(User)
User.hasOne(Cart)
Cart.belongsToMany(Product, { through: CartItem })
Product.belongsToMany(Cart, { through: CartItem })
Enter fullscreen mode Exit fullscreen mode
carts
Enter fullscreen mode Exit fullscreen mode
sequelize.sync({ force: true })
    .then(() => {
        console.log("Created new table and added relations to it")
    })
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')
Created new table and added relations to it
Enter fullscreen mode Exit fullscreen mode
User.findByPk(1)
    .then(v => {
        if (v == null)
        {
            console.log("User not found. Creating it")
            User.create({
                name: "Dummy User",
                email: "dummy@user.com"
                })
                .then(() => {
                    console.log("User Created")
                })
                .catch(console.warn)
        }
        else
        {
            console.log("User found. Not creating a new one")
        }
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



User not found. Creating it
User Created
Enter fullscreen mode Exit fullscreen mode
User.findByPk(1)
    .then(v => {
        v.createProduct({
            title: "Product #1",
            description: "Sample description for Product #1",
            price: 12.88,
        })
            .then(() => {
                console.log("Created product");
            })
            .catch(console.warn)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



Created product
Enter fullscreen mode Exit fullscreen mode
User.findByPk(1)
    .then(v => {
        v.createProduct({
            title: "Product #2",
            description: "Sample description for Product #2",
            price: 12.88,
        })
            .then(() => {
                console.log("Created product");
            })
            .catch(console.warn)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



Created product
Enter fullscreen mode Exit fullscreen mode
User.findByPk(1)
    .then(v => {
        v.createProduct({
            title: "Product #3",
            description: "Sample description for Product #3",
            price: 12.88,
        })
            .then(() => {
                console.log("Created product");
            })
            .catch(console.warn)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



Created product
Enter fullscreen mode Exit fullscreen mode

Getting the Cart

User.findByPk(1)
    .then(v => {
        v.getCart()
            .then(v => {
                console.log(v)
            })
            .catch(console.warn)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')
null
Enter fullscreen mode Exit fullscreen mode

Since there is no cart, therefore it's null

Creating a cart for the user, if it's not created

User.findByPk(1)
    .then(v => {
        v.getCart()
            .then(c => {
                if (c == null) {
                    console.log("No cart found. Creating one")
                    v.createCart()
                        .then(() => {
                            console.log("Cart created")
                        })
                        .catch(console.warn)
                } else {
                    console.log("Cart exists")
                }
            })
            .catch(console.warn)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')
No cart found. Creating one
Cart created
Enter fullscreen mode Exit fullscreen mode
User.findByPk(1)
    .then(v => {
        v.getCart()
            .then(v => {
                console.log(v.dataValues)
            })
            .catch(console.warn)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')
{
  id: 1,
  createdAt: 2020-03-31T07:58:41.000Z,
  updatedAt: 2020-03-31T07:58:41.000Z,
  userId: 1
}
Enter fullscreen mode Exit fullscreen mode

Getting products from cart

User.findByPk(1)
    .then(v => {
        v.getCart()
            .then(c => {
                c.getProducts()
                    .then(p => {
                        console.log(p)
                    })
                    .catch(console.warn)
            })
            .catch(console.warn)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')
[]
Enter fullscreen mode Exit fullscreen mode

Since no product has been added to the cart, the list is empty

Adding products to the cart

let product_id = null
Enter fullscreen mode Exit fullscreen mode
Product.findOne({ where: { title: "Product #2" }})
    .then(product => {
        product_id = product.id
    })
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')
Enter fullscreen mode Exit fullscreen mode
product_id
Enter fullscreen mode Exit fullscreen mode
2
Enter fullscreen mode Exit fullscreen mode
User.findByPk(1)
    .then(v => {
        let cart;
        v.getCart() // getting the cart
            .then(c => {
                cart = c; // assigning for later use
                return c.getProducts({ where: { id: product_id } }) // returning all the products in the cart
            })
            .then(products => {
                let product = null;
                if (products.length > 0) { // select one product
                    product = products[0]
                }

                let quantity = 1 // the quantity set to one
                if (product) { // if product exits
                    // get the current quantity
                    // add one to it
                    // add the same object of product model to the cart
                    CartItem
                        .findOne({ productId: product.id, cartId: cart.id })
                        .then(item => {
                            let oldQuantity = item.quantity; 
                            quantity = oldQuantity + 1;
                            cart
                                .addProduct(product, { through: { quantity } })
                                .then(() => console.log("Updated the quantity"))
                                .catch(console.warn)
                        })
                         .catch(console.warn)

                } else {
                    // find the product by id
                    // add it to the cart through cart item model, setting the quantity
                    Product
                        .findByPk(product_id)
                        .then(product => {
                            cart.addProduct(product, { through: { quantity } })
                            console.log("Added new product");
                        })
                        .catch(console.warn)
                }
            })
            .catch(console.warn)
    })
    .catch()
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')


(sequelize) Warning: Model attributes (productId, cartId) passed into finder method options of model cart_items, but the options.where object is empty. Did you forget to use options.where?


Updated the quantity
Enter fullscreen mode Exit fullscreen mode

Deleting the item in the cart

User.findByPk(1)
    .then(u => {
        let cart = null;
        u
            .getCart()
            .then(c => {
                cart = c;
                return c.getProducts({ where: { id: product_id } })
            })
            .then(products => {
                const product = products[0];
                CartItem
                    .findOne({ productId: product_id,  cartId: cart.id })
                    .then(item => {
                        item
                            .destroy()
                            .then(() => console.log("Deleted the product from cart"))
                            .catch(console.warn)
                    })
                    .catch(console.warn);
            })
            .catch(console.warn)
    })
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')


(sequelize) Warning: Model attributes (productId, cartId) passed into finder method options of model cart_items, but the options.where object is empty. Did you forget to use options.where?


Deleted the product from cart
Enter fullscreen mode Exit fullscreen mode
CartItem
    .findAll()
    .then(v => console.log(v.length))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
Promise [Object] {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined
}



warning: please use IANA standard timezone format ('Etc/GMT0')
0
Enter fullscreen mode Exit fullscreen mode

Discussion (0)