Agradeceríamos tu apoyo para difundir nuestras secciones en referencia a las ciencias de la computación.
Solución:
Necesitas definir tu propia on
cláusula de la JOIN
declaración
ModelA.findAll(
include: [
model: ModelB,
on:
col1: sequelize.where(sequelize.col("ModelA.col1"), "=", sequelize.col("ModelB.col1")),
col2: sequelize.where(sequelize.col("ModelA.col2"), "=", sequelize.col("ModelB.col2"))
,
attributes: [] // empty array means that no column from ModelB will be returned
]
).then((modelAInstances) =>
// result...
);
Con respecto a la duda de @TophatGordon en el comentario de la respuesta aceptada: si necesitamos tener asociaciones configuradas en el modelo o no.
También revisé el problema de github planteado en 2012 que todavía está en abierto estado.
Así que también estaba en la misma situación e intentaba configurar mi propio ON
condición para la unión externa izquierda.
Cuando traté directamente de usar el on: ...
dentro de Table1.findAll(...include Table2 with ON condition...)
, no funcionó. Me arrojó un error:
EagerLoadingError [SequelizeEagerLoadingError]: Table2 is not associated to Table1!
Mi caso de uso fue hacer coincidir dos no primarios-key columnas de Table1 a dos columnas en Table2 en la combinación externa izquierda. Mostraré cómo y qué logré:
No se confunda con los nombres de las tablas y las columnas, ya que tuve que cambiarlos de los originales que usé.
Entonces tuve que crear una asociación en Table1 (Tarea) como:
Task.associate = (models) =>
Task.hasOne(models.SubTask,
foreignKey: 'someId', // <--- one of the column of table2 - SubTask: not a primary key here in my case; can be primary key also
sourceKey: 'someId', // <--- one of the column of table1 - Task: not a primary key here in my case; can be a primary key also
scope:
[Op.and]: sequelize.where(sequelize.col("Task.some_id_2"),
// '=',
Op.eq, // or you can use '=',
sequelize.col("subTask.some_id_2")),
,
as: 'subTask',
// no constraints should be applied if sequelize will be creating tables and unique keys are not defined,
//as it throws error of unique constraint
constraints: false,
);
;
Así que la consulta de búsqueda se ve así:
Task.findAll(
where: whereCondition,
// attributes: ['id','name','someId','someId2'],
include: [
model: SubTask, as: 'subTask', // <-- model name and alias name as defined in association
attributes: [], // if no attributes needed from SubTask - empty array
,
],
);
Consulta resultante:
- Una condición coincidente se toma de [foreignKey] = [sourceKey]
- La segunda condición de coincidencia se obtiene por
sequelize.where(...)
utilizada enscope:...
select "Task"."id", "Task"."name", "Task"."some_id" as "someId", "Task"."some_id_2" as "someId2" from "task" as "Task" left outer join "sub_task" as "subTask" on "Task"."some_id" = "subTask"."some_id" and "Task"."some_id_2" = "subTask"."some_id_2";
Otro enfoque para lograr lo mismo que el anterior para resolver problemas cuando se usa Table1 en include, es decir, cuando Table1 aparece como tabla de segundo nivel o se incluye desde otra tabla, digamos Table0
Task.associate = (models) =>
Task.hasOne(models.SubTask,
foreignKey: 'someId', // <--- one of the column of table2 - SubTask: not a primary key here in my case; can be primary key also
sourceKey: 'someId', // <--- one of the column of table1 - Task: not a primary key here in my case; can be a primary key also
as: 'subTask',
// <-- removed scope -->
// no constraints should be applied if sequelize will be creating tables and unique keys are not defined,
//as it throws error of unique constraint
constraints: false,
);
;
Entonces, la consulta de búsqueda de Table0 se ve así: Además, ForeignKey y sourceKey no se considerarán, ya que ahora usaremos custom on: ...
Table0.findAll(
where: whereCondition,
// attributes: ['id','name','someId','someId2'],
include:
model: Task, as: 'Table1AliasName', // if association has been defined as alias name
include: [
model: SubTask, as: 'subTask', // <-- model name and alias name as defined in association
attributes: [], // if no attributes needed from SubTask - empty array
on:
[Op.and]: [
sequelize.where(
sequelize.col('Table1AliasName_OR_ModelName.some_id'),
Op.eq, // '=',
sequelize.col('Table1AliasName_OR_ModelName->subTask.some_id')
),
sequelize.where(
sequelize.col('Table1AliasName_OR_ModelName.some_id_2'),
Op.eq, // '=',
sequelize.col('Table1AliasName_OR_ModelName->subTask.some_id_2')
),
],
,
],
);
Omita la parte de abajo si sus tablas ya están creadas...
Establecer restricciones para falsecomo si Sequelize intentara crear la segunda tabla (Subtarea), podría arrojar un error (DatabaseError [SequelizeDatabaseError]: there is no unique constraint matching given keys for referenced table "task")
debido a la siguiente consulta:
crear una tabla si no existe "sub_task" ("some_id" INTEGER, "some_id_2" INTEGER hace referencia a "tarea" ("some_id") en la cascada de eliminación en la cascada de actualización, "data" INTEGER);
si establecemos restricción: falsecrea esta consulta a continuación que no generará un error de restricción único ya que estamos haciendo referencia a una columna no principal:
crear tabla si no existe "sub_task" ("some_id" INTEGER, "some_id_2" INTEGER, "data" INTEGER);
Te mostramos las comentarios y valoraciones de los lectores
Si posees algún recelo y capacidad de modernizar nuestro enunciado eres capaz de dejar una acotación y con gusto lo interpretaremos.