Як зробити запити приєднання за допомогою Sequelize на Node.js


104

Я використовую секелізацію 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);
        });

Моє питання - як я можу змінити код, щоб використовувати стиль ORM замість SQL-запиту?

Відповіді:


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

Наведений вище запит може виглядати дещо складніше порівняно з тим, що ви опублікували, але те, що він робить, це в основному просто псевдонім усіх стовпців таблиці користувачів, щоб переконатися, що вони розміщені у правильній моделі при поверненні та не змішанні з моделлю публікацій

Крім цього, ви помітите, що це ПРИЄДНАЙТЕ замість вибору з двох таблиць, але результат повинен бути однаковим

Подальше читання:


7
Що робити, якщо я хочу приєднатися лише до користувачів, які народились у 1984 році? У SQL я би зробив:SELECT * FROM posts JOIN users ON users.id = posts.user_id WHERE users.year_birth = 1984
Івазару

1
Усі посилання мертві не :-(
Manwal

1
Чи було це питання коли-небудь розміщене у відповіді?
theptrk

1
Чи потрібні нам обоє, або одного достатньо: User.hasMany (Повідомлення, {ForeignKey: 'user_id'}) Post.belongsTo (Користувач, {ForeignKey: 'user_id'})
antew

1
@antew Під час дзвінка User.hasMany(Post)ви додаєте методи / атрибути до об'єкта "Користувач", а під час виклику Post.belongsTo(User)додаєте методи до класу "Пост". Якщо ви завжди телефонуєте з одного напрямку (наприклад, User.getPosts ()), вам не потрібно нічого додавати до об'єкта Post. Але приємно мати методи з обох сторін.
Райан Шиллінгтон

170

Хоча прийнята відповідь не є технічно помилковою, вона не відповідає на початкове запитання, а також на запитання, яке я отримав у коментарях. Але я зрозумів це, так ось що.

Якщо ви хочете знайти всі повідомлення, у яких є користувачі (і лише ті, у яких є користувачі), де SQL виглядатиме так:

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

Що семантично те саме, що і оригінальний SQL OP:

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

тоді це те, що ви хочете:

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

Установка, необхідна для істинного, є ключем до створення внутрішнього з'єднання. Якщо ви хочете ліве зовнішнє з'єднання (де ви отримуєте всі повідомлення, незалежно від того, чи є користувач, пов’язаний), то змініть потрібну на помилкову або залиште її, оскільки це за замовчуванням:

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

Якщо ви хочете знайти всі повідомлення, що належать користувачам, рік народження яких - 1984, ви хочете:

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

Зверніть увагу, що за замовчуванням потрібно вказати, що потрібно, як тільки ви додаєте пункт де в.

Якщо ви хочете, щоб усі повідомлення, незалежно від того, чи є приєднаний користувач, але якщо є користувач, то лише ті, хто народився в 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
Дякую дуже, це було корисно
Нео

6
так, чудова відповідь
duxfox--

так що репрезентує posts.user_id = users.idу вашій послідовності? спасибі
hanzichi

5
Ця відповідь настільки вичерпна, що її слід пов’язати з документом Sequelize
Джорджо Андретті

2
Чудовий підручник, який я шукав. Дякую багато
Андрій Райан

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

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

2

У моєму випадку я зробив наступне. У UserMaster userId є ПК, а в UserAccess userId - FK від UserMaster

UserAccess.belongsTo(UserMaster,{foreignKey: 'userId'});
UserMaster.hasMany(UserAccess,{foreignKey : 'userId'});
var userData = await UserMaster.findAll({include: [UserAccess]});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.