공식문서 짜증나서 내가 그냥 한 번에 정리하는 시퀄라이즈 공식문서1
한 번에 여러 모델을 가져오는 query이다.
required: true
옵션 : associated model 이 존재하는 객체만을 Return 하도록 강제한다.
User.findAll({
include: {
model: Task,
required: true
}
});
'$nested.column'
syntax 를 이용한다.
User.findAll({
where: {
'$Instruments.size$': { [Op.ne]: 'small' }
},
include: [{
model: Tool,
as: 'Instruments'
}]
});
Foo.findAll({
include: [
{
model: Bar,
required: true
},
{
model: Baz,
where: /* ... */
},
Qux // Shorthand syntax for { model: Qux } also works here
]
})
paranoid 를 쓰면 Model.destroy()
로 모델을 삭제하였을 때 db에서 바로 사라지는 것이 아니라,deleted_at
field 가 추가되게 된다.
이렇게 deleted_at
을 통해 db에 남아있는 객체들을 모두 가져오려면
User.findAll({
include: [{
model: Tool,
as: 'Instruments',
where: { size: { [Op.ne]: 'small' } },
paranoid: false
}]
});
nested 가 있을 경우에는 top-level에 order
옵션을 넣어준다.
sorting 하고 싶은 model 을 배열의 가장 처음에 넣어준다.
Company.findAll({
include: Division,
order: [ [Division, 'name', 'ASC'] ]
})
Compnay.findAll({
include : {model : Division, as : 'Div' },
order : [
[{model: Division, as : 'Div'}, 'name'. 'DESC' ]
]
})
getQuestionWithManyComment: async(question_id) => {
const answer = await Answer.findAll({
attributes : ['id', 'question_id',
[sequelize.fn('count', sequelize.col('Comments.id')), 'comment_count']],
include : [{
model: Comment,
attributes : []
}],
group : ['id'],
order : [[sequelize.literal('comment_count'), 'DESC']]
});
return answer;
}
answer 객체에 대하여 연관된 comment 의 개수로 sorting 하는 함수. 죽겠다.
// Fetch 10 instances/rows
Project.findAll({ limit: 10 });
// Skip 8 instances/rows
Project.findAll({ offset: 8 });
// Skip 5 instances and fetch the 5 after that
Project.findAll({ offset: 5, limit: 5 });
const amount = await Project.count({
where: {
id: {
[Op.gt]: 25
}
}
});
console.log(`There are ${amount} projects with an id greater than 25`);
category_id 가 null
일 때엔 모든 카테고리에 대한 답변을 가져오고, not null
일 때에는 해당하는 category_id 값만 가져오기
const category_attr = {};
if ( category_id ) {
category_attr[Op.eq]= category_id;
} else {
category_attr[Op.not]= null;
}
const answers = await Answer.findAll({
where: {
user_id,
content: {
[Op.not]: null,
},
[Op.or]: [{'$Question.title$' : {
[Op.like]: `%${query}%`}},
{content : {
[Op.like]: `%${query}`
}}
],
'$Question.category_id$': category_attr,
public_flag: public_attr,
},
include : {
model : Question,
attributes: [],
},
raw : true,
order :[['answer_date', 'DESC']],
limit,
offset : (page - 1) * 10,
});
answers 를 선언해주는 곳에서 '$Question.category_id$': category_attr
부분을 보면 된다.
$
를 써 준 이유는 category_id 를 Answer 객체에서 바로 참조하지 못하고 Answer와 연결된 Question 객체에서 참조하여야 하기 때문에 nested model 인 Question을 이용하기 위해 사용한 것.
where: {[Op.or]: [{ a: 5 }, { b: 6 }]},
이런 식으로 써주면 a = 5 or b = 6인 객체가 반환되고
where : { someAttributes: { [Op.or]: [5, 6],}}
이렇게 이용해주면 someAttributes가 5 or 6 인 객체들이 반환된다.
이를 이용하여 복수의 user_id
들에 대한 Answer 를 한 번에 가져오려면,
let users = await Follow.findAll({
where: {
followed_id: user_id,
},
attributes: [['follower_id', 'id']],
raw: true,
ex : [1,2,3,4]
users = users.map(i => i.id);
const answers = await Answer.findAll({
where : {
user_id : {
[Op.or] : users,
},
public_flag: true,
content: {
[Op.not] : null,
}
},
attributes:['id'],
order: [['answer_date', 'DESC']],
raw : true,
limit: 10,
offset: (page - 1) * 10,
});
belongsToMany
의 join table의 경우 primary key 가 생성되지 않는다. 직접 model 에서 id 를 추가해줘야 하는데..!
const { User } = require("./index");
const Sequelize = require('sequelize');
module.exports = (sequelize, DataTypes) => {
return sequelize.define('RecentSearch', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
...
};
point 는 기존의
Datatypes.INTEGER
대신에Sequelize.INTEGER
를 이용해줘야 한다는 것.
시퀄라이즈 객체를 console 에 찍어보면
[
Comment {
dataValues: {
id: 1,
content: '잘 읽고 갑니다~',
public_flag: false,
user_id: 1,
answer_id: 1,
createdAt: 2021-01-01T09:06:53.000Z,
updatedAt: 2021-01-01T09:27:43.000Z,
Children: [Array]
},
_previousDataValues: {
id: 1,
content: '잘 읽고 갑니다~',
public_flag: false,
user_id: 1,
answer_id: 1,
createdAt: 2021-01-01T09:06:53.000Z,
updatedAt: 2021-01-01T09:27:43.000Z,
Children: [Array]
},
_changed: Set(0) {},
_options: {
isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
include: [Array],
includeNames: [Array],
includeMap: [Object],
includeValidated: true,
attributes: [Array],
raw: true
},
isNewRecord: false,
Children: [ [Comment] ]
}
]
이런식으로 dataValues 외에 다른 값들이 추가적으로 많이 들어가있다. 바로 이 객체를 return 시에는 dataValues 만 자동으로 전달되기 때문에 문제가 없지만, 객체에 새로운 변수를 추가하거나 기존 변수의 값을 변경하는 것이 불가했다.
comment.id = 1
, comment.dataValues.id = 3
이 모두 작동하지 않았다.comment = await Comment.findAll({ raw : true });
raw:true
옵션을 설정하면 dataValues 만 return 된다.
하지만 include
하는 테이블이 있는 경우, 모든 변수가 객체의 형태 대신 comment.Children.id
이런 방식으로 변수 이름을 가지고 나타난다.
nested: true
옵션을 더해주면 include 도 가능해진다. 하지만 두 개 이상의 객체를 Include 하지는 못하고 하나씩만 해준다. child 가 2개인 경우에 parent 역시 2번 등장하는 것. const re = answer.dataValues;
re.comment = comments.map(m => m.dataValues)
직접 접근해주기.
result = result.map(el => el.get({ plain: true }));
solution2와 같은 방법. findAll 한 데이터에서 dataValues 부분만 반환된다.
계속 고생하다가 그냥
comments = comments.map(i => i.dataValues);
를 써주기로 결정.
for (parent of comments) {
parent.Children = parent.Children.map(i => i.dataValues)};
child 의 경우 위와 같이 처리해주었다.
let answer = await Answer.findOne({
where : {
id : answer_id,
},
include : {
model: Comment,
include : {
model : Comment,
as : 'Children'
},
// where : {
// parent_id : null,
// }
},
attributes: { exclude: ['createdAt', 'updatedAt'] }
});
answer 에서 댓글과 대댓글을 불러오기 위한 쿼리문이다.
원래 Include 를 해줘도 객체가 없으면 빈 배열([])을 반환하는데, 이 경우에는 answer 객체가 존재하여도 연관된 Comment 가 없으면 null 이 됐다.
→ 아이고 where 절을 추가하면 option의 required
가 true
가 된다고 한다. 시퀄라이즈 공식 문서
와... 정리 너무 잘하셨네요! 정말 좋은 정보 감사합니다:)
구독하고 갑니다~~! ㅈㅇ