Cara membuat kueri penggabungan menggunakan Sequelize di Node.js

104

Saya menggunakan ORM sekuel; semuanya bagus dan bersih, tetapi saya mengalami masalah saat menggunakannya dengan joinkueri. Saya memiliki dua model: pengguna dan posting.

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

Saya ingin kueri yang merespons dengan kiriman dengan info pengguna yang membuatnya. Dalam kueri mentah, saya mendapatkan ini:

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

Pertanyaan saya adalah bagaimana saya dapat mengubah kode untuk menggunakan gaya ORM daripada kueri SQL?

Jose Sosa
sumber

Jawaban:

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

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

Yang akan memberimu

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

Kueri di atas mungkin terlihat sedikit rumit dibandingkan dengan apa yang Anda posting, tetapi yang dilakukannya pada dasarnya hanyalah aliasing semua kolom tabel pengguna untuk memastikan mereka ditempatkan ke dalam model yang benar ketika dikembalikan dan tidak tercampur dengan model posting

Selain itu, Anda akan melihat bahwa ia melakukan GABUNG daripada memilih dari dua tabel, tetapi hasilnya harus sama

Bacaan lebih lanjut:

Jan Aagaard Meier
sumber
7
Bagaimana jika saya hanya ingin bergabung dengan Pengguna yang lahir pada tahun 1984? Dalam SQL saya akan melakukan:SELECT * FROM posts JOIN users ON users.id = posts.user_id WHERE users.year_birth = 1984
Iwazaru
1
Semua tautan mati bukan :-(
Manwal
1
Apakah pertanyaan itu pernah diposting dalam pertanyaan yang sudah dijawab?
theptrk
1
Apakah kita membutuhkan keduanya atau satu sudah cukup: User.hasMany (Post, {foreignKey: 'user_id'}) Post.belongsTo (User, {foreignKey: 'user_id'})
antew
1
@antew Ketika Anda memanggil User.hasMany(Post)Anda menambahkan metode / atribut ke objek Pengguna, dan ketika Anda memanggil Post.belongsTo(User)Anda menambahkan metode ke kelas Post. Jika Anda selalu menelepon dari satu arah (mis. User.getPosts ()) maka Anda tidak perlu menambahkan apapun ke objek Post. Tetapi senang memiliki metode di kedua sisi.
Ryan Shillington
170

Meskipun jawaban yang diterima tidak salah secara teknis, itu tidak menjawab pertanyaan asli atau pertanyaan tindak lanjut di komentar, yang saya cari di sini. Tapi saya menemukan jawabannya, jadi ini dia.

Jika Anda ingin menemukan semua Postingan yang memiliki Pengguna (dan hanya yang memiliki pengguna) di mana SQL akan terlihat seperti ini:

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

Yang secara semantik sama dengan SQL asli OP:

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

maka inilah yang Anda inginkan:

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

Pengaturan yang diperlukan menjadi benar adalah kunci untuk menghasilkan gabungan dalam. Jika Anda ingin left outer join (di mana Anda mendapatkan semua Postingan, terlepas dari apakah ada pengguna yang ditautkan), ubah diperlukan menjadi false, atau biarkan karena itu default:

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

Jika Anda ingin menemukan semua Kiriman milik pengguna yang tahun lahirnya pada tahun 1984, Anda pasti menginginkan:

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

Perhatikan bahwa required adalah benar secara default segera setelah Anda menambahkan klausa where in.

Jika Anda menginginkan semua Postingan, terlepas dari apakah ada pengguna yang dilampirkan tetapi jika ada pengguna, maka hanya yang lahir pada tahun 1984, lalu tambahkan kembali bidang yang diperlukan:

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

Jika Anda menginginkan semua Postingan yang namanya "Sunshine" dan hanya jika itu milik pengguna yang lahir pada tahun 1984, Anda akan melakukan ini:

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

Jika Anda menginginkan semua Postingan yang namanya "Sinar Matahari" dan hanya jika itu milik pengguna yang lahir di tahun yang sama yang cocok dengan atribut post_year pada postingan, Anda akan melakukan ini:

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

Saya tahu, tidak masuk akal jika seseorang membuat postingan tentang tahun mereka lahir, tapi itu hanya sebuah contoh - ikuti saja. :)

Saya menemukan ini (kebanyakan) dari dokumen ini:

Ryan Shillington
sumber
9
Terima kasih banyak, ini berguna
Neo
6
ya, jawaban yang bagus
duxfox--
jadi apa yang diwakili posts.user_id = users.iddalam sekuel Anda? terima kasih
hanzichi
5
Jawaban ini sangat lengkap sehingga harus ditautkan dalam dokumen Sequelize
Giorgio Andretti
2
Sepotong besar tutorial yang telah saya cari. Terima kasih banyak
Andrew Rayan
6
Model1.belongsTo(Model2, { as: 'alias' })

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

Dalam kasus saya, saya melakukan hal berikut. Di UserMaster userId adalah PK dan di UserAccess userId adalah FK dari UserMaster

UserAccess.belongsTo(UserMaster,{foreignKey: 'userId'});
UserMaster.hasMany(UserAccess,{foreignKey : 'userId'});
var userData = await UserMaster.findAll({include: [UserAccess]});
Renish Gotecha
sumber