Sequelize 시리즈
- [Node.js] Sequelize(1) - sequelize와 sequelize-cli
- [Node.js] sequelize(2) - 모델 정의하기
- [Node.js] sequelize(3) - CRUD + RESTful 게시판 만들기
- [Node.js] sequelize(4) - 관계 설정( association ) 및 게시판 댓글 구현하기
- [Node.js] sequelize(5) - seed 활용하기
- [Node.js] sequelize(6) - 제약조건 추가 ( custom validate )
- [Node.js] sequelize(7) - 검색기능에 필요한 query operator
- [Node.js] sequelize(8) - pagination
2019. 08. 11 수정
대부분의 웹 서비스에서 검색 기능은 많이 필요합니다.
이번 글에서는 sequelize의 findAll() 메서드를 호출할 때 옵션을 추가하여, 검색기능을 활용하는 방법에 대해 알아보도록 하겠습니다.
( sequelize query에 대한 공식문서는 여기를 참고해주세요. )
1. 준비작업
sequelize-cli로 테스트 모델을 생성하기 위해, 아래의 명령어를 실행합니다.
# sequelize model:create --name "test" --attributes "postName:string, postWriter:string"
이어서 생성된 모델 파일과 migration 파일을 수정합니다.
/models/test.js
'use strict';
module.exports = (sequelize, DataTypes) => {
var test = sequelize.define('test', {
postName: {
type: DataTypes.STRING,
},
postWriter: {
type: DataTypes.STRING,
}
});
return test;
};
/migrations/20171206073442-create-test.js
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('tests', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
postName: {
type: Sequelize.STRING,
},
postWriter: {
type: Sequelize.STRING,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('tests');
}
};
migrations 파일을 수정했으니, migration 명령어를 실행합니다.
# sequelize db:migration
다음으로 MySQL에 테스트 데이터를 추가했는데요,
sequelize가 검색을 어떻게 수행하는지 알아보기 위해 postName을 유사하게 작성해보았습니다.
2. 유사 검색
유사 검색이란 와일드 카드를 활용하여, 완전히 똑같지 않은 검색어를 입력해도 일부 내용이 같으면, 검색하는 것을 말합니다.
예를 들어, 데이터가 위의 사진과 같을 때,
- 일치 검색(유사 검색과 반대 개념)으로 postName을 "sequelize"로 검색하면 1번 게시글만 출력이 됩니다.
- 반면에 유사 검색으로 "%sequelize%"를 검색하면 1, 2, 3, 4번 게시글이 출력됩니다.
즉, 일치검색은 완전히 똑같은 문자열을, 유사검색은 문자열이 포함되기만 하면 검색을 허용합니다.
대부분의 DB는 유사검색으로 % 기호를 사용합니다.
- 검색 키워드로 %sequelize 를 작성하면
- "sequelize"앞에 어떤 문자열이 와도 검색 조건에 충족되지만, "sequelize" 뒤에 있는 문자열은 검색할 수 없습니다.
- 예를 들어, 위의 사진에서 3번은 검색이 가능하지만, 2번은 검색조건에 충족되지 않습니다.
- sequelize%는 반대로 "sequelize"로 시작하는 문자열을 검색하고,
- %sequelize%는 "sequelize" 문자열을 포함하기만 하면 검색을 합니다.
이제 sequelize로 유사 검색을 구현해보도록 하겠습니다.
/routes/index.js
const express = require('express');
const models = require("../models");
const sequelize = require("sequelize");
const Op = sequelize.Op;
const router = express.Router();
router.get("/likeSearch/:searchWord", function(req, res, next){
let searchWord = req.params.searchWord
models.test.findAll({
where:{
postName: {
[Op.like]: "%" + searchWord + "%"
}
}
})
.then( result => {
res.json(result)
})
.catch( err => {
console.log(err)
})
})
module.exports = router;
- 서버를 실행한 후, 브라우저에서 localhost:3000/likeSearch/sequelize 경로로 요청을 보냅니다.
- 실제로는 클라이언트가 form의 input으로 보낸 값을 검색어로 사용하겠지만, 여기서는 편의상 URL에 작성했습니다.
- 그러면 "sequelize" 문자열이 req.params.searchWord에 담겨있을겁니다.
- 그리고 sequelize의 findAll() 메서드를 사용하여 모든 데이터를 조회합니다.
- 즉, findAll() 메서드를 호출할 때 유사검색을 조건절로 추가한 모습입니다.
- 그런데 Op 객체를 정의하기 위해서는 sequelize 모듈 객체가 있어야 하므로 sequelize모듈도 require해야 합니다.
- 이 때 sequelize에서 유사검색을 지원하는 query operators에는 [Op.like] 속성이 있는데요, 검색하고 싶은 단어 옆에 % 기호를 붙여줍니다.
- [Op.like] 속성을 사용하기 위해서는 Op 객체가 정의되어 있어야 합니다.
유사 검색 조회 결과는 다음과 같이 "sequelize" 단어가 포함하기만 하면 조회됩니다.
즉, id 1~4까지의 데이터만 조회되었습니다.
3. OR 검색
OR 검색이란 검색하고자 하는 조건을 여러 개 추가하여 이 중 하나라도 만족하면, 그 데이터를 불러오는 operator입니다.
바로 코드를 작성하고 결과를 살펴보도록 하겠습니다.
/routes/index.js
const express = require('express');
const models = require("../models");
const sequelize = require("sequelize");
const Op = sequelize.Op;
var router = express.Router();
router.get("/orSearch/:searchWord", function(req, res, next){
let searchWord = req.params.searchWord
models.test.findAll({
where:{
[Op.or]: [
{
postName: {
[Op.like]: "%" + searchWord + "%"
}
},
{
postWriter: {
[Op.like]: "%" + searchWord + "%"
}
}
]
}
})
.then( result => {
res.json(result)
})
.catch( err => {
console.log(err)
})
})
module.exports = router;
이번에는 브라우저에 localhost:3000/orSearch/A 경로로 요청을 보내면, 아래와 같은 결과를 확인 할 수 있습니다.
이 예제는 postName 또는 postWriter에 "A"를 유사 검색으로 하여, 두 컬럼중에 "A" 문자열이 하나라도 존재하는 데이터를 조회하는 코드입니다.
유사 검색 예제와 다른 것은,
- where 프로퍼티의 값에 postName과 같이 테이블의 컬럼 이름을 작성하는 것이 아닌, [Op.or]를 프로퍼티로 작성하고, 값으로 배열을 할당했습니다.
- 그리고 배열의 각 원소에는 객체가 할당되는데, 객체는 컬럼 이름과 유사 검색 조건을 프로퍼티로 작성했습니다.
- [Op.or]은 배열의 각 원소를 탐색하여 조건을 만족하면 그 row를 반환하고, 조건을 만족하지 않으면 다음 원소로 넘어갑니다.
4. Ordering
이번에는 게시글을 출력할 때, 정렬 하는 방법에 대해 알아보도록 하겠습니다.
예제에서는 가장 기본적인 정렬을 사용법을 작성했으며, 자세한 사항을 문서를 참고해주세요 !
/route/index.js
const express = require('express');
const models = require("../models");
const router = express.Router();
router.get("/likeSearch", function(req, res, next){
models.test.findAll({
order: [['postWriter', 'DESC']]
})
.then( result => {
res.json(result)
})
.catch( err => {
console.log(err)
})
})
module.exports = router;
정렬을 하기 위해서는 findAll() 메서드를 호출할 때 옵션으로 order 프로퍼티를 작성합니다.
유사 검색, OR 검색과 달리 where 프로퍼티를 사용하지 않습니다.
order 프로퍼티의 값으로는 배열안에 배열을 작성해야 하는데, 그 이유는 여러 기준을 갖고 정렬을 사용할 수 있기 때문입니다.
이 예제에서는 postWriter를 기준으로 내림차순으로 정렬하는 코드입니다.
따라서 postWriter의 첫 글자가 "s -> f -> E -> D -> C ... " 순서로 출력이 되는 것을 확인할 수 있습니다.
이상으로 복잡한 검색을 할 때 유용한 sequelize query에 대해 알아보았습니다.