mysql - Cómo hacer consultas de combinación usando Sequelize en Node.js
orm sequelize.js (3)
Estoy usando la secuencia de ORM; todo es genial y limpio, pero tuve un problema cuando lo uso con consultas de join
. Tengo dos modelos: usuarios y publicaciones.
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);
})
Quiero una consulta que responda con una publicación con la información del usuario que la realizó. En la consulta cruda, obtengo esto:
db.seq.query(''SELECT * FROM posts, users WHERE posts.user_id = users.id '').success(function(rows){
res.json(rows);
});
Mi pregunta es ¿cómo puedo cambiar el código para usar el estilo ORM en lugar de la consulta SQL?
Si bien la respuesta aceptada no es técnicamente incorrecta, no responde a la pregunta original ni a la pregunta de seguimiento en los comentarios, que fue lo que vine a buscar aquí. Pero lo descubrí, así que aquí va.
Si desea buscar todas las publicaciones que tienen usuarios (y solo las que tienen usuarios) donde el SQL se vería así:
SELECT * FROM posts INNER JOIN users ON posts.user_id = users.id
Que es semánticamente lo mismo que el SQL original de OP:
SELECT * FROM posts, users WHERE posts.user_id = users.id
entonces esto es lo que quieres:
Posts.findAll({
include: [{
model: User,
required: true
}]
}).then(posts => {
/* ... */
});
El ajuste requerido para verdadero es la clave para producir una unión interna. Si desea una combinación externa izquierda (donde obtiene todas las Publicaciones, independientemente de si hay un usuario vinculado), cambie la requerida a falso o desactívela, ya que es la predeterminada:
Posts.findAll({
include: [{
model: User,
// required: false
}]
}).then(posts => {
/* ... */
});
Si quiere encontrar todas las Publicaciones que pertenecen a usuarios cuyo año de nacimiento es en 1984, querría:
Posts.findAll({
include: [{
model: User,
where: {year_birth: 1984}
}]
}).then(posts => {
/* ... */
});
Tenga en cuenta que lo requerido es verdadero por defecto tan pronto como agrega una cláusula Where en.
Si desea todas las Publicaciones, independientemente de si hay un usuario conectado pero si hay un usuario, solo aquellos que nacieron en 1984, agregue el campo requerido de nuevo en:
Posts.findAll({
include: [{
model: User,
where: {year_birth: 1984}
required: false,
}]
}).then(posts => {
/* ... */
});
Si quieres todas las publicaciones donde el nombre es "Sunshine" y solo si pertenece a un usuario que nació en 1984, harías esto:
Posts.findAll({
where: {name: "Sunshine"},
include: [{
model: User,
where: {year_birth: 1984}
}]
}).then(posts => {
/* ... */
});
Si quiere todas las publicaciones donde el nombre es "Sunshine" y solo si pertenece a un usuario que nació en el mismo año que coincide con el atributo post_year en la publicación, haría esto:
Posts.findAll({
where: {name: "Sunshine"},
include: [{
model: User,
where: ["year_birth = post_year"]
}]
}).then(posts => {
/* ... */
});
Lo sé, no tiene sentido que alguien haga una publicación el año en que nació, pero es solo un ejemplo: vaya con eso. :)
Me di cuenta (principalmente) de este documento:
Model1.belongsTo(Model2, { as: ''alias'' })
Model1.findAll({include: [{model: Model2 , as: ''alias'' }]},{raw: true}).success(onSuccess).error(onError);
User.hasMany(Post, {foreignKey: ''user_id''})
Post.belongsTo(User, {foreignKey: ''user_id''})
Post.find({ where: { ...}, include: [User]})
Que te dará
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 consulta anterior puede parecer un poco complicada en comparación con lo que publicaste, pero lo que hace es básicamente aliasing todas las columnas de la tabla de los usuarios para asegurarse de que se colocan en el modelo correcto cuando se devuelve y no se mezcla con el modelo de mensajes
Aparte de eso, notará que hace un JOIN en lugar de seleccionar de dos tablas, pero el resultado debería ser el mismo
Otras lecturas: