Cách thực hiện các truy vấn tham gia bằng cách sử dụng Sequelize trên Node.js


104

Tôi đang sử dụng ORM phần tiếp theo; mọi thứ đều tuyệt vời và sạch sẽ, nhưng tôi đã gặp sự cố khi sử dụng nó với joincác truy vấn. Tôi có hai mô hình: người dùng và bài đăng.

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);
})

Tôi muốn một truy vấn phản hồi bằng một bài đăng với thông tin của người dùng đã tạo ra nó. Trong truy vấn thô, tôi nhận được điều này:

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

Câu hỏi của tôi là làm cách nào để thay đổi mã để sử dụng kiểu ORM thay vì truy vấn SQL?

Câu trả lời:


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

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

Cái nào sẽ cho bạn

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`;

Truy vấn ở trên có thể trông hơi phức tạp so với những gì bạn đã đăng, nhưng những gì nó thực hiện về cơ bản chỉ là tạo răng cưa cho tất cả các cột của bảng người dùng để đảm bảo chúng được đặt vào đúng mô hình khi trả về và không bị lẫn với mô hình bài đăng.

Khác với điều đó, bạn sẽ nhận thấy rằng nó thực hiện một THAM GIA thay vì chọn từ hai bảng, nhưng kết quả sẽ giống nhau

Đọc thêm:


7
Điều gì sẽ xảy ra nếu tôi chỉ muốn tham gia với Người dùng sinh năm 1984? Trong SQL, tôi sẽ làm:SELECT * FROM posts JOIN users ON users.id = posts.user_id WHERE users.year_birth = 1984
Iwazaru

1
Tất cả các liên kết đều không chết :-(
Manwal

1
Câu hỏi đó đã bao giờ được đăng trong một câu hỏi đã trả lời chưa?
theptrk

1
Chúng ta cần cả hai hay một cái là đủ: User.hasMany (Đăng, {ForeignKey: 'user_id'}) Post.belongsTo (Người dùng, {ForeignKey: 'user_id'})
antew 21/02/17

1
@antew Khi bạn gọi, User.hasMany(Post)bạn thêm phương thức / thuộc tính vào đối tượng Người dùng và khi bạn gọi, Post.belongsTo(User)bạn thêm phương thức vào lớp Post. Nếu bạn luôn gọi từ một hướng (ví dụ: User.getPosts ()) thì bạn không cần thêm bất cứ thứ gì vào đối tượng Bài đăng. Nhưng thật tuyệt khi có các phương pháp của cả hai bên.
Ryan Shillington

170

Mặc dù câu trả lời được chấp nhận không sai về mặt kỹ thuật, nhưng nó không trả lời câu hỏi ban đầu cũng như câu hỏi tiếp theo trong các nhận xét, đó là những gì tôi đến đây tìm kiếm. Nhưng tôi đã tìm ra nó, vì vậy hãy bắt đầu.

Nếu bạn muốn tìm tất cả các Bài đăng có Người dùng (và chỉ những Bài đăng có Người dùng) thì SQL sẽ trông như thế này:

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

Về mặt ngữ nghĩa, điều này giống với SQL gốc của OP:

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

thì đây là những gì bạn muốn:

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

Đặt yêu cầu thành true là chìa khóa để tạo ra liên kết bên trong. Nếu bạn muốn kết hợp bên ngoài bên trái (nơi bạn nhận được tất cả các Bài đăng, bất kể có người dùng được liên kết hay không) thì hãy thay đổi bắt buộc thành false hoặc bỏ nó đi vì đó là mặc định:

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

Nếu bạn muốn tìm tất cả Bài đăng của người dùng có năm sinh là 1984, bạn muốn:

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

Lưu ý rằng bắt buộc là đúng theo mặc định ngay sau khi bạn thêm mệnh đề where vào.

Nếu bạn muốn có tất cả Bài đăng, bất kể có người dùng đính kèm hay không nhưng nếu có người dùng thì chỉ những người sinh năm 1984, sau đó thêm lại trường bắt buộc vào:

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

Nếu bạn muốn tất cả các Bài đăng có tên là "Sunshine" và chỉ khi nó thuộc về người dùng sinh năm 1984, bạn sẽ làm như sau:

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

Nếu bạn muốn tất cả các Bài đăng có tên là "Sunshine" và chỉ khi nó thuộc về một người dùng sinh cùng năm khớp với thuộc tính post_year trên bài đăng, bạn sẽ làm như sau:

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

Tôi biết, sẽ không hợp lý nếu ai đó đăng một bài vào năm họ sinh ra, nhưng đó chỉ là một ví dụ - hãy làm với nó. :)

Tôi đã tìm ra điều này (chủ yếu) từ tài liệu này:


9
Cảm ơn bạn rất nhiều, điều này rất hữu ích
Neo

6
vâng, câu trả lời tuyệt vời
duxfox--

vậy điều gì đại diện cho phần tiếp posts.user_id = users.idtheo của bạn? cảm ơn
hanzichi

5
Câu trả lời này là rất đầy đủ nó phải được liên kết trong doc Sequelize của
Giorgio Andretti

2
Lớn mảnh của hướng dẫn mà tôi đã tìm for.Thanks rất nhiều
Andrew Rayan

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

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

2

Trong trường hợp của tôi, tôi đã làm điều sau đây. Trong UserMaster, userId là PK và trong UserAccess, userId là FK của UserMaster

UserAccess.belongsTo(UserMaster,{foreignKey: 'userId'});
UserMaster.hasMany(UserAccess,{foreignKey : 'userId'});
var userData = await UserMaster.findAll({include: [UserAccess]});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.