티스토리 뷰

※ Sequelize 개념 소개 

▶ 우선, Sequelize란 Node.js ORM 프레임워크이다. 

기본적으로 DB연결은 네트워크 통신을 필요로하고, 따라서 비동기 처리를 위해 Promise 기반으로 만들어져있다. 

 

▶ Sequelize 하나로 다양한 DBMS (Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server)를 지원하지만,

각 SQL을 DBMS 특성마다 성능을 최적화시킬 수 없다는 아쉬움이 있다. 

 

https://sequelize.org/master/

 

Manual | Sequelize

Constraints & Circularities Adding constraints between tables means that tables must be created in the database in a certain order, when using sequelize.sync. If Task has a reference to User, the User table must be created before the Task table can be crea

sequelize.org

 

※  프로젝트 적용 후기 

▶ Sequelize를 사용하면 SQL문을 직접 작성하지 않아도 된다는 장점(?)이 있지만, SQL을 잘 아는 개발자라면 굳이 사용할 필요가 있나 싶었다. 그러나, 공부에 의의를 두고 NodeJS 기반의 프로젝트를 진행하면서 모든 SQL문을 적용해보았다. 

 

▶ 프로젝트에 Sequelize 적용한 후기 :

생각보다  Sequelize Documentation이 다양한 SQL문을 다루지 않았고,

구글 선생님도 그다지 도움되지 않아서 혼자 고군분투해야 했다. 

직접 SQL 쿼리를 다이렉트로 작성할 수도 있지만, 포기하지 않고 Sequelize로 모든 쿼리를 변환한것이 참 뿌듯했다.^^


※ MySQL <->  Sequelize  플젝 시 구현한 코드 공유 

1.  주문 횟수가 가장 많은 TOP5 회원 구하기 

getVipMembers: async function(){
        try{
            // Member와 OrderMain 조인
            // 다(N).findAll
            const result = await db.OrderMain.findAll({
                attributes: [
                    'Member.member_name', 'order_memberid', 'Member.member_email',
                    [db.Sequelize.fn('count', db.Sequelize.col('order_memberid')), 'cnt']
                ],
                include: [{ 
                    model: db.Member
                 }],
                 group: ['order_memberid'],
                 order: [[db.Sequelize.literal('cnt'), 'DESC']],
                 limit: 5
             });
             return result;
        }catch(error){
            
            throw error;
        }
    }

▶ 주의) include를 사용하려면 모델에 관계설정이 필요하다. 

class OrderMain extends Model {
        static associate(models) { 
            // 다 대 일(Member)
            models.OrderMain.belongsTo(models.Member, {foreignKey:"order_memberid", targetKey:"member_id"});
        }
    }

 

2.  최근 한 달간 가입한 회원 수 구하기 

getRecentJoinCount: async function(){
        try{
            // 한달 전 날짜 구하는 로직 
            const curr = new Date();
            const lastDayofLastMonth = (new Date(curr.getYear(), curr.getMonth(), 0)).getDate();
            if(curr.getDate() > lastDayofLastMonth) {
                curr.setDate(lastDayofLastMonth); 
            }
            curr.setMonth(curr.getMonth() - 1);
            const result = await db.Member.count({
                where: {
                    join_date: { [Op.gte]: curr}
                }
            });
            return result;
        }catch(error){
            throw error;
        }
    }

 

3.  총 판매 금액 구하기 

sumtotalprice: async function(){
        try{
            const result = await db.OrderMain.sum('order_price');
            return result;
        }catch(error){
            throw error;
        }
   }

 

4.  최근 한 달  판매량 (해당 월) 구하기 

totalpriceByMonth: async function(targetMonth){
        try{
            const result = await db.OrderMain.findOne({
                attributes: [
                    [sequelize.fn('month', sequelize.col("order_date")), 'month'],
                    [sequelize.fn('sum', sequelize.col("order_price")), 'sum']
                ],
                where: {
                    [Op.and]: [
                      sequelize.where(sequelize.fn('month', sequelize.col('order_date')), targetMonth)
                    ]
                }
            });
            return result.dataValues;
        }catch(error){
            throw error;
        }
    }

 

5.  최근 한 달  주문수 (해당 월) 구하기 

salesCountByMonth: async function(targetMonth){
        try{
            const result = await db.OrderMain.findOne({
                attributes: [
                    [sequelize.fn('month', sequelize.col("order_date")), 'month'],
                    [sequelize.fn('count', sequelize.col("order_id")), 'count']
                ],
                where: {
                    [Op.and]: [
                      sequelize.where(sequelize.fn('month', sequelize.col('order_date')), targetMonth)
                    ]
                }
            });
            return result.dataValues;
        }catch(error){
            throw error;
        }
    }

 

6. 조건에 따른 정렬 구현하기 

- 주의) order 속성을 const가 아닌 let으로 선언하기 

list: async function(pager, orderType){
        try{
            let order = [["sabang_buycount", "DESC"]]; 
            if(orderType){
                if(orderType == 'view'){
                    order = [["sabang_viewcount", "DESC"]];
                }else if(orderType == 'high'){
                    order = [["sabang_saleprice", "DESC"]];
                }else if(orderType == 'low'){
                    order = [["sabang_saleprice", "ASC"]];
                }
            }
            const result = await db.Sabang.findAll({
                order,
                limit: pager.rowsPerPage,
                offset: pager.startRowIndex
            }); 
            return result;
        }catch(error){
            throw error;
        }
    }

 

7.  삭제할때 delete 아니고 destroy

deleteProduct: async function(product){
        try{
            // 1. 상품 테이블 삭제 
            await db.Product.destroy({where: {product_id: product.product_id}});

            // 2. 사방 테이블 가격 갱신 
            await db.Sabang.decrement({
                sabang_price: parseInt(product.product_price),
                sabang_saleprice: parseInt(product.product_price)
            }, {where:{sabang_id: product.sabang_id}});

        }catch(error){
            throw error;
        }
    }

 

8. 생성 

createProduct: async function(product){
        try{
            // 1. 상품 테이블 등록 
            const dbBoard = await db.Product.create(product);
           
            // 2. 사방 테이블 가격 갱신 
            await db.Sabang.increment({
                sabang_price: parseInt(product.product_price),
                sabang_saleprice: parseInt(product.product_price)
            }, {where:{sabang_id: product.sabang_id}});

            return dbBoard;
        }catch(error){
            throw error;
        }
    }

 

9. 주문 Id를 이용해 주문 정보와 회원 정보 동시에 가져오기 

getOrderWithMemberInfo: async function(order_id){
        try{
            // 다 대 일 associate 관계 설정 이용 
            const order = await db.OrderMain.findOne({where: {order_id}});
            order.dataValues.Member = await order.getMember();
            return order;
        }catch(error){
            throw error;
        }
    }

▶ 주의) OrderMain 클래스에 "다대일" 관계 설정을 해야 getMember() 메소드(관계 설정 시 자동 생성)를 사용할 수 있다. 

class OrderMain extends Model {
        static associate(models) { 
            // 다 대 일(Member)
            models.OrderMain.belongsTo(models.Member, {foreignKey:"order_memberid", targetKey:"member_id"});
        }
    }