본문 바로가기

Node.js

ORM(Object Relation Mapping)을 이용해보자! 2편 CRUD! 나는 데이터와 친구다!


시작하기 전에


해당 블로그에 작성되는 글은 주인장의 지극히 주관적인 생각이 다수이며, 대부분의 지식은 구글링을 통해 얻고 있기 때문에 옳지않은 정보가 있습니다. 

잘못된 부분이나 수정해야 하는 부분이 있다면 과감히 덧글을 남겨주세요! 모르는게 많은 새싹입니다



오늘의 주제


오늘은 ORM(Object Relation Mapping)을 이용해보자 2편, "CRUD! 나는 데이터와 친구다!" 입니다. 1편에서는 ORM이 무엇인지 무슨 장단점이 있으며, ORM 중에서도 Sequelize.js를 이용하여 어떻게 객체를 정의하며 객체간의 관계를 정의하는지. 가장 기초적인 내용에 대해서 다뤘다면, 2편에서는 실제로 데이터를 검색하고 추가하고 삭제하고 수정하는지 CRUD작업에 초점을 맞춰 내용을 구성하겠습니다. 재미있게 읽어주세요~!



원하는 데이터를 찾아라 (Select)

Sequelize.js에서 데이터를 찾기위해서는 Find와 관련된 메소드를 사용합니다. 우선 무슨 메소드들이 있고 어떤 기능을 하는지 알아봅시다.

findAll()
원하는 조건에 따라 원하는 데이터를 전부 가져옵니다.
select.findAll = (callback) => {
  return user.findAll({
    // attributes: ['id', 'password'], // select id, password ~
    // attributes: ['user_id', ['password', 'pw']] // select id, password as pw
    attributes: [[Op.fn('count', Op.col('user_id')), 'no-id']]
  })
  .then(result => {
    // console.log('FindAll result', result)
    callback(result)
  })
  .catch(err => {
    console.log(err)
    callback(err)
  })
}
findOne()
원하는 조건에 따라 하나의 row만을 가져옵니다.
select.findOne = (data, callback) => {
  return user.findOne({ where : { password : '123'}})
    .then(result => {
      callback(result)
    })
    .catch(err => {
      callback(err)
    })
}
findById()
아이디 겁색을 통해 원하는 row를 가져옵니다.
/*
  아이디를 통해 하나의 로우를 찾는 메소드 입니다.
  뭔가... 컬럼명이 id인 친구들만 찾아주는 것 같아요.
*/
select.findById = (data, callback) => {
  return user.findById(data)
    .then(result => {
      // console.log('FindAll result', result)
      callback(result)
    })
    .catch(err => {
      console.log(err)
      callback(err)
    })
}
findOrCreate()
처음 데이터를 조회하고 원하는 데이터가 존재하지 않으면 데이터를 생성합니다.
/*
 조회를 시도하고 원하는 결과가 없을 경우 로우를 생성합니다.
 find or create 사용시에는 결과값으로 2개의 인자가 반환되기 때문에
 spread 메소드를 사용합니다.
*/
select.findOrCreate = (data, callback) => {
  return user.findOrCreate(
    {
      where : { user_id : data },
      defaults: { password: '5555' }
    })
    .spread((user, create) => {
      user && callback(user)
      create && callback(create)
    })
    .catch(err => {
      callback(err)
    })
  }
findAndCountAll()
검색한 데이터를 전체 검색하고 검색된 데이터의 개수를 반환합니다.
/*
  conbines findAll and count 조회와 카운트의 혼합형 입니다.
  count - integer, total number record matching the where clause and other filters due to associations,
          within the limit and offset range
          정수로 반환되며 레코드의 총 숫자를 반환합니다. 
  rows - an array of objects, the records matching the where clause and other filters due to associations,
         within the limit and offest range
         배열객체로 반환 됩니다.
  
  Offset과 limit를 통해 두가지 모두 제한을 줄 수 있습니다.
*/
select.findAndCountAll = (callback) => {
  return user.findAndCountAll({
    where : { 
      password : {
        [Op.like]: 'foo%'
      },
    },
  })
  .then(result => {
    console.log(result.count)
    console.log(result.rows)
    callback(result)
  })
}


#검색시 필요한 옵션들


Where절 옵션

 where: {
    id: {
      [Op.and]: {a: 5},           // AND (a = 5)
      [Op.or]: [{a: 5}, {a: 6}],  // (a = 5 OR a = 6)
      [Op.gt]: 6,                // id > 6
      [Op.gte]: 6,               // id >= 6
      [Op.lt]: 10,               // id < 10
      [Op.lte]: 10,              // id <= 10
      [Op.ne]: 20,               // id != 20
      [Op.between]: [6, 10],     // BETWEEN 6 AND 10
      [Op.notBetween]: [11, 15], // NOT BETWEEN 11 AND 15
      [Op.in]: [1, 2],           // IN [1, 2]
      [Op.notIn]: [1, 2],        // NOT IN [1, 2]
      [Op.like]: '%hat',         // LIKE '%hat'
      [Op.notLike]: '%hat',       // NOT LIKE '%hat'
      [Op.iLike]: '%hat',         // ILIKE '%hat' (case insensitive)  (PG only)
      [Op.notILike]: '%hat',      // NOT ILIKE '%hat'  (PG only)
      [Op.overlap]: [1, 2],       // && [1, 2] (PG array overlap operator)
      [Op.contains]: [1, 2],      // @> [1, 2] (PG array contains operator)
      [Op.contained]: [1, 2],     // <@ [1, 2] (PG array contained by operator)
      [Op.any]: [2,3]            // ANY ARRAY[2, 3]::INTEGER (PG only)
    },

Join 옵션

return user.findAndCountAll({
 // include는 config에서 정해준 관계에 따라 join을 가능하도록 해주는 명령어
   include: [
    /*
    where 절에 들어있는 컬럼은 기본적으로 required 상태가 된다. 
    model 부분은 조인하고자 하는 model이 대상이 되며 
    where 절에 있는 컬럼은 조인의 대상이 된다.
    */
    { model: book, required: true },
    { model: book, where: {user_id : true} },
   // Belong-To-Many인 모델에서 where절을 사용하기 위해서는
   through: {
      attribute: ['cloumn1', 'column2', 'column3'],
      where: { compeleted: true},
    }}, 
   ],
   limit: 10,
   offset: 1,
})


원하는 데이터를 추가하자 ( Insert )

원하는 데이터를 추가하는 방법은 간단하다. 원하는 모델을 선택한후 Object를 column명에 대해 매핑만 시켜주면 된다.
insert.create = async function (model, data, callback) {
  console.log('UserModel create', data.username)
  return await model.create({
    password: data.password,
  })
  .then(result => {
    callback(result)
  })
}


원하는 데이터로 바꿔보자 ( Update)

원하는 데이터로 상태를 변경하거나 값을 변경할 수 있습니다.
// username이 dongieer인 컬럼에 대하여 dongsu로 변경하는 구문입니다.

update.update = async (model, data, callback) => {
  return model.update(
    { username : 'dongineer'},
    { where : { username : 'dongsu'} },
  )
  .then(result => {
    callback(result)
  })
  .catch(err => {
    callback(err)
  })
}


원하는 데이터를 삭제하자 ( Delete )

각종 조건에 맞춰 원하는 데이터를 삭제할 수 있다. 간단한 예제와 위에서 배운 조건문들을 이용한다면 원하는 데이터를 삭제할 수 있을 것이다. 덤으로 Model을 날려버리는 것도 추가해봤습니다.
Delete.destory = async (model, data, callback) => {
  console.log('userRows create')
  return await model.destory({
    where : { username: data.username }
  })
  .then(result => {
    callback(result)
  })
  .catch(err => {
    callacb(err)
  })
}

Delete.drop = async (model, data, callback) => {
  return model.drop()
  .then(result => {
    callback(result)
  })
  .catch(err => {
    callback(err)
  })
}



이번 ORM을 이용해보자 2편에서는 Sequelize.js를 이용통하여

CURD 작업을 하는 방법에 대해 알아보았습니다. 사실 크게 어려운 내용은 다루지 않았어요.

제가 모르거든요 (웃음웃음)

더 자세한 내용은 공식문서에 잘 나와있답니다.

공식 문서를 보시려면 여기를 눌러주세요.



황급히 ORM을 이용해보자 2편! CRUD! 나는 데이터와 친구다! 를 마치도록 하겠습니다. ( _ _ )