I'm trying to build a query in sequelize which basically makes a join between two tables: Resource and ContentTag, which are in a manyToMany relationship: In sql the query I'd like to obtain whould look like this:
`SELECT * FROM Resources-Ctag
NATURAL JOIN (SELECT * FROM Resource-Ctag WHERE ContentTag.keyword="A")as ResourceWithTagA
NATURAL JOIN (SELECT * FROM Resource-Ctag WHERE ContentTag.keyword="B")as ResourceWithTagB
WHERE ContentTag.keyword="C"`
Where Resources-Ctag is hypotetically the bridge table which associates resources to contentTags. The objective is to retrieve all resources that contains at least all the three tag together: A, B , C.
Here is the Resource model in sequelize:
import { ContentTag } from "./content_tag";
export class Resource extends Model {
// Default incremental ID
public id!: number;
// Model attributes
public name!: string;
public description!: string;
public format!: string;
public path!: string;
public metadata!: any;
public typologyTagId!: string;
public readonly createdAt!: Date;
public readonly updatedAt!: Date;
// Associations
public addContentTag!: HasManyAddAssociationMixin<ContentTag, number>;
public getContentTags!: HasManyGetAssociationsMixin<ContentTag>;
public setContentTags!: HasManySetAssociationsMixin<ContentTag, number>;
public static initialize(sequelize) {
this.init(
{
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
},
name: {
type: DataTypes.STRING,
allowNull: false,
unique: false,
},
description: {
type: DataTypes.STRING,
allowNull: true,
unique: false,
},
format: {
type: DataTypes.STRING,
allowNull: false,
unique: false,
},
path: {
type: DataTypes.STRING,
allowNull: false,
unique: false,
},
metadata: {
type: DataTypes.JSON,
allowNull: true,
unique: false,
},
},
{
sequelize,
timestamps: true,
paranoid: true,
tableName: "resource",
}
);
}
}
And here is the ContentTag Model:
export class ContentTag extends Model {
// Default incremental ID
public id!: string;
// Model attributes
public keyword!: string;
public static initialize(sequelize) {
this.init(
{
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
},
keyword: {
type: DataTypes.STRING,
allowNull: false,
unique: false,
},
},
{
sequelize,
timestamps: true,
createdAt: false,
updatedAt: false,
tableName: "content_tag",
}
);
}
}
I've tried this but it doesnt work:
router.get("/", async (req: any, res: Response) => {
try {
const { typologyTag, timeFrom, timeTo, author } = req.query;
const cTags = JSON.parse(req.query.contentTags)
const where = {};
const include = [
{
model: TypologyTag,
as: "typologyTag",
},
{
model: User,
as: "author",
},
{
model: ContentTag,
as: "contentTags",
},
];
if (typologyTag) {
include[0]["where"] = { keyword: { [Op.eq]: typologyTag } };
};
if (author) {
include[1]["where"] = { displayName: { [Op.eq]: author } };
};
if (timeFrom && timeTo) {
where["createdAt"] = {
[Op.lt]: timeTo,
[Op.gt]: new Date(timeFrom)
};
} else if (timeFrom) {
where["createdAt"] = {
[Op.gt]: new Date(timeFrom)
};
} else if (timeTo) {
where["createdAt"] = {
[Op.lt]: new Date(timeTo)
};
};
if (cTags && cTags.length != 0 && cTags.reduce(
(accumulator, currentValue) => accumulator && currentValue,
true)) {
include[2]["where"] = { keyword: { [Op.eq]: cTags[0] } };
if (cTags[1]) {
include[2]["include"] = [{
model: Resource,
as: "resources",
include: [{
model: ContentTag,
as: "contentTags",
where: { keyword: { [Op.eq]: cTags[1] } },
include: [{
model: Resource,
as: "resources",
include: [{
model: ContentTag,
as: "contentTags",
where: { keyword: { [Op.eq]: cTags[2] } },
}]
}]
}]
}]
}
};
const result = await Resource.findAll({
where: where,
include: include,
});
....
I made such a huge effort thinking about that solution but now I realise it obviously can't work. Now I have no more clue on how to solve that query.