我正在使用 Sequelize 来处理 MariaDB 数据库,我需要对两列进行全文搜索:
order.comment
和 order.orderProducts.product.name
。
我已在
order.name
、product.name
和 user.name
列上添加了 FULLTEXT 索引。
这是我的代码:
if (search) {
where = Sequelize.literal(
`MATCH(order.comment) AGAINST('*${search}*' IN BOOLEAN MODE) OR
MATCH(orderProducts.product.name) AGAINST('*${search}*' IN BOOLEAN MODE) OR
MATCH(user.name) AGAINST('*${search}*' IN BOOLEAN MODE)`,
);
}
const orders = await this.orderModel.findAndCountAll({
subQuery: false,
limit,
offset,
distinct: true,
order: [['id', 'DESC']],
where,
include: [
{
model: User,
},
{
model: OrderProduct,
include: [
{
model: Product,
},
],
},
],
});
当我搜索某些内容时,出现错误:
Unknown column 'orderProducts.product.name' in 'where clause'
没有
MATCH(orderProducts.product.name) AGAINST('*${search}*' IN BOOLEAN MODE)
一切正常。
我不明白为什么会发生这种情况以及如何解决它。我尝试了不同的选择,但没有成功。
我的模特:
@Table({
tableName: 'orders',
indexes: [{ type: 'FULLTEXT', fields: ['comment'] }],
})
export class Order extends Model<Order> {
@Column({
type: DataType.INTEGER,
primaryKey: true,
autoIncrement: true,
})
id: number;
@Column({ type: DataType.TEXT, allowNull: false })
comment: string;
@HasMany(() => OrderProduct, { foreignKey: 'orderId' })
orderProducts: OrderProduct[];
}
@Table({
tableName: 'products',
indexes: [{ type: 'FULLTEXT', fields: ['name'] }],
})
export class Product extends Model<Product> {
@Column({
type: DataType.INTEGER,
primaryKey: true,
autoIncrement: true,
})
id: number;
@Column({ type: DataType.STRING, unique: true, allowNull: false })
name: string;
@HasMany(() => OrderProduct, { foreignKey: 'productId' })
orderProducts: OrderProduct[];
}
@Table({ tableName: 'order_products' })
export class OrderProduct extends Model<OrderProduct> {
@Column({
type: DataType.INTEGER,
primaryKey: true,
autoIncrement: true,
})
id: number;
@Column({ type: DataType.INTEGER, allowNull: false })
price: number;
@ForeignKey(() => Product)
@Column({ type: DataType.INTEGER })
productId: number;
@ForeignKey(() => Order)
@Column({ type: DataType.INTEGER })
orderId: number;
@BelongsTo(() => Product, { foreignKey: 'productId' })
product: Product;
@BelongsTo(() => Order, { foreignKey: 'orderId' })
order: Order;
}
附注 我尝试过这些变化:
/* ----1---- */
if (search) {
where = Sequelize.literal(
`MATCH(product.name) AGAINST('*${search}*' IN BOOLEAN MODE)`,
);
}
/* ----2---- */
if (search) {
where = Sequelize.literal(
`MATCH(Product.name) AGAINST('*${search}*' IN BOOLEAN MODE)`,
);
}
/* ----3---- */
if (search) {
where = Sequelize.literal(
`MATCH(OrderProducts.Product.name) AGAINST('*${search}*' IN BOOLEAN MODE)`,
);
}
错误是一样的。
SQL 查询出错:
sql: SELECT count(DISTINCT(`Order`.`id`)) AS `count` FROM `orders` AS `Order` LEFT OUTER JOIN `users` AS `user` ON `Order`.`userId` = `user`.`id` LEFT OUTER JOIN `order_products` AS `orderProducts` ON `Order`.`id` = `orderProducts`.`orderId` LEFT OUTER JOIN `products` AS `orderProducts->product` ON `orderProducts`.`productId` = `orderProducts->product`.`id` WHERE MATCH(orderProducts.product.name) AGAINST('*hello*' IN BOOLEAN MODE); - parameters:[]
你可以看到Sequelize正在加入这样的产品:
LEFT OUTER JOIN `products` AS `orderProducts->product`
给它一个别名orderProducts->product,其中包含特殊字符,所以使用时需要用反引号括起来。所以你的文字 sql 应该使用列:
`orderProducts->product`.name
转义反引号以将其包含在模板文字中:
`MATCH(\`orderProducts->product\`.name) AGAINST('*${search}*' IN BOOLEAN MODE)`,