web-dev-qa-db-fra.com

Comment créer des requêtes de jointure à l'aide de Sequelize on Node.js

J'utilise séquelle ORM; tout est génial et propre, mais j'ai eu un problème lorsque je l'utilisais avec les requêtes join. J'ai deux modèles: les utilisateurs et les messages.

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

Je veux une requête qui répond avec un message avec les informations de l'utilisateur qui l'a faite. Dans la requête brute, j'obtiens ceci:

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

Ma question est comment puis-je changer le code pour utiliser le style ORM au lieu de la requête SQL?

75
Jose Sosa
User.hasMany(Post, {foreignKey: 'user_id'})
Post.belongsTo(User, {foreignKey: 'user_id'})

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

Qui vous donnera

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

La requête ci-dessus peut paraître un peu compliquée par rapport à ce que vous avez posté, mais elle consiste simplement à créer un aliasing pour toutes les colonnes de la table users afin de s'assurer qu'elles sont placées dans le bon modèle lorsqu'elles sont renvoyées et qu'elles ne sont pas mélangées avec le modèle posts

En dehors de cela, vous remarquerez qu'il fait une jointure au lieu de choisir parmi deux tables, mais le résultat devrait être le même.

Lectures complémentaires:

98
Jan Aagaard Meier

Bien que la réponse acceptée ne soit pas techniquement erronée, elle ne répond pas à la question initiale ni à la question suivante dans les commentaires, ce que je recherchais ici. Mais je l'ai compris, alors voilà.

Si vous souhaitez rechercher toutes les publications ayant des utilisateurs (et uniquement celles ayant des utilisateurs) où le code SQL ressemblerait à ceci:

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

Ce qui est sémantiquement la même chose que le SQL original de l'OP:

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

alors c'est ce que vous voulez:

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

La définition de true est la clé pour créer une jointure interne. Si vous souhaitez une jointure externe gauche (où vous obtenez toutes les publications, qu'il y ait ou non un utilisateur lié), définissez obligatoire sur false, ou laissez-la désactivée, car il s'agit de la valeur par défaut:

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

Si vous souhaitez rechercher toutes les publications appartenant à des utilisateurs dont l'année de naissance est 1984, vous souhaitez:

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

Notez que requis est vrai par défaut dès que vous ajoutez une clause where dans.

Si vous voulez toutes les publications, qu’il y ait ou non un utilisateur, mais s'il y en a un, alors uniquement celles qui sont nées en 1984, ajoutez le champ requis dans:

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

Si vous voulez tous les messages dont le nom est "Sunshine" et uniquement s'il appartient à un utilisateur né en 1984, procédez comme suit:

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

Si vous voulez toutes les publications dont le nom est "Sunshine" et uniquement si elles appartiennent à un utilisateur né la même année et qui correspond à l'attribut post_year de la publication, procédez comme suit:

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

Je sais, il n’est pas logique de penser que quelqu'un posterait l'année de sa naissance, mais ce n'est qu'un exemple. :)

J'ai compris ceci (principalement) à partir de ce doc:

84
Ryan Shillington
Model1.belongsTo(Model2, { as: 'alias' })

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

Dans mon cas j'ai fait la chose suivante. Dans le UserMaster serId est PK et dans UserAccess serId est FK de UserMaster

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