Node.js에서 Sequelize를 사용하여 조인 쿼리를 만드는 방법


104

sequelize ORM을 사용하고 있습니다. 모든 것이 훌륭하고 깨끗하지만 join쿼리 와 함께 사용할 때 문제가 발생했습니다 . 사용자와 게시물의 두 가지 모델이 있습니다.

var User = db.seq.define('User',{
    username: { type: db.Sequelize.STRING},
    email: { type: db.Sequelize.STRING},
    password: { type: db.Sequelize.STRING},
    sex : { type: db.Sequelize.INTEGER},
    day_birth: { type: db.Sequelize.INTEGER},
    month_birth: { type: db.Sequelize.INTEGER},
    year_birth: { type: db.Sequelize.INTEGER}

});

User.sync().success(function(){
    console.log("table created")
}).error(function(error){
    console.log(err);
})


var Post = db.seq.define("Post",{
    body: { type: db.Sequelize.TEXT },
    user_id: { type: db.Sequelize.INTEGER},
    likes: { type: db.Sequelize.INTEGER, defaultValue: 0 },

});

Post.sync().success(function(){
    console.log("table created")
}).error(function(error){
    console.log(err);
})

나는 그것을 만든 사용자의 정보가 담긴 게시물로 응답하는 쿼리를 원합니다. 원시 쿼리에서 다음을 얻습니다.

db.seq.query('SELECT * FROM posts, users WHERE posts.user_id = users.id ').success(function(rows){
            res.json(rows);
        });

내 질문은 SQL 쿼리 대신 ORM 스타일을 사용하도록 코드를 어떻게 변경할 수 있습니까?

답변:


129
User.hasMany(Post, {foreignKey: 'user_id'})
Post.belongsTo(User, {foreignKey: 'user_id'})

Post.find({ where: { ...}, include: [User]})

당신에게 줄 것입니다

SELECT
  `posts`.*,
  `users`.`username` AS `users.username`, `users`.`email` AS `users.email`,
  `users`.`password` AS `users.password`, `users`.`sex` AS `users.sex`,
  `users`.`day_birth` AS `users.day_birth`,
  `users`.`month_birth` AS `users.month_birth`,
  `users`.`year_birth` AS `users.year_birth`, `users`.`id` AS `users.id`,
  `users`.`createdAt` AS `users.createdAt`,
  `users`.`updatedAt` AS `users.updatedAt`
FROM `posts`
  LEFT OUTER JOIN `users` AS `users` ON `users`.`id` = `posts`.`user_id`;

위의 쿼리는 게시 한 내용에 비해 약간 복잡해 보일 수 있지만 기본적으로 사용자 테이블의 모든 열에 별칭을 지정하여 반환 될 때 올바른 모델에 배치되고 posts 모델과 혼합되지 않도록하는 것입니다.

그 외에는 두 테이블에서 선택하는 대신 JOIN을 수행하지만 결과는 동일해야합니다.

추가 읽기 :


7
1984 년에 태어난 사용자 만 가입하려면 어떻게해야합니까? SQL에서 나는 할 것입니다 :SELECT * FROM posts JOIN users ON users.id = posts.user_id WHERE users.year_birth = 1984
Iwazaru dec

1
모든 링크는 완전히 방전되지 않았 :-(
Manwal

1
해당 질문이 답변 된 질문에 게시 된 적이 있습니까?
theptrk 2015

1
둘 다 필요합니까 아니면 하나면 충분합니까 : User.hasMany (Post, {foreignKey : 'user_id'}) Post.belongsTo (User, {foreignKey : 'user_id'})
antew

1
@antew 호출 User.hasMany(Post)할 때 User 개체에 메서드 / 속성을 추가하고 호출 Post.belongsTo(User)할 때 Post 클래스에 메서드를 추가합니다. 항상 한 방향에서 호출하는 경우 (예 : User.getPosts ()) Post 객체에 아무것도 추가 할 필요가 없습니다. 그러나 양쪽에 방법이있는 것이 좋습니다.
Ryan Shillington

170

받아 들여진 대답은 기술적으로 틀린 것은 아니지만 원래 질문에 대한 대답도 아니고 댓글에있는 후속 질문에도 대답하지 않았습니다. 그러나 나는 그것을 알아 냈습니다.

사용자가있는 모든 게시물 (및 사용자가있는 게시물 만)을 찾으려면 SQL이 다음과 같이 표시됩니다.

SELECT * FROM posts INNER JOIN users ON posts.user_id = users.id

OP의 원래 SQL과 의미 상 동일합니다.

SELECT * FROM posts, users WHERE posts.user_id = users.id

그러면 이것이 당신이 원하는 것입니다.

Posts.findAll({
  include: [{
    model: User,
    required: true
   }]
}).then(posts => {
  /* ... */
});

true로 설정해야 내부 조인을 생성 할 수 있습니다. 왼쪽 외부 조인 (사용자가 연결되어 있는지 여부에 관계없이 모든 게시물을 가져 오는 위치)을 원하면 required를 false로 변경하거나 기본값이므로 해제 상태로 둡니다.

Posts.findAll({
  include: [{
    model: User,
//  required: false
   }]
}).then(posts => {
  /* ... */
});

출생 연도가 1984 년인 사용자의 모든 게시물을 찾으려면 다음을 원할 것입니다.

Posts.findAll({
  include: [{
    model: User,
    where: {year_birth: 1984}
   }]
}).then(posts => {
  /* ... */
});

where 절을 추가하자마자 required는 기본적으로 true입니다.

첨부 된 사용자가 있는지 여부에 관계없이 모든 게시물을 원하지만 사용자가있는 경우 1984 년에 태어난 사용자 만있는 경우 필수 필드를 다시 추가합니다.

Posts.findAll({
  include: [{
    model: User,
    where: {year_birth: 1984}
    required: false,
   }]
}).then(posts => {
  /* ... */
});

이름이 "Sunshine"인 모든 게시물을 원하고 1984 년에 태어난 사용자의 경우에만 다음과 같이하면됩니다.

Posts.findAll({
  where: {name: "Sunshine"},
  include: [{
    model: User,
    where: {year_birth: 1984}
   }]
}).then(posts => {
  /* ... */
});

이름이 "Sunshine"인 모든 게시물을 원하고 게시물의 post_year 속성과 일치하는 동일한 연도에 태어난 사용자에게 속한 경우에만 다음을 수행합니다.

Posts.findAll({
  where: {name: "Sunshine"},
  include: [{
    model: User,
    where: ["year_birth = post_year"]
   }]
}).then(posts => {
  /* ... */
});

누군가가 자신이 태어난 해에 게시물을 올릴 것이라는 것은 말이 안되지만 이것은 단지 예일뿐입니다. :)

나는이 문서에서 (대부분) 이것을 알아 냈습니다.


9
대단히 감사합니다. 이것은 유용했습니다
Neo

6
예, 훌륭한 답변
duxfox-- dec.

그래서 posts.user_id = users.id당신의 속편에서 무엇을 상징 합니까? 감사합니다
hanzichi 19 년

5
이 답변은 너무 철저해서 Sequelize의 문서에 연결되어야합니다
Giorgio Andretti

2
내가 for.Thanks에게 많이 찾고있다 튜토리얼의 큰 조각
앤드류 Rayan

6
Model1.belongsTo(Model2, { as: 'alias' })

Model1.findAll({include: [{model: Model2  , as: 'alias'  }]},{raw: true}).success(onSuccess).error(onError);

2

제 경우에는 다음과 같이했습니다. UserMaster에서 userId 는 PK이고 UserAccess에서 userId 는 UserMaster의 FK입니다.

UserAccess.belongsTo(UserMaster,{foreignKey: 'userId'});
UserMaster.hasMany(UserAccess,{foreignKey : 'userId'});
var userData = await UserMaster.findAll({include: [UserAccess]});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.