Drizzle | 使用生成列进行全文搜索
本指南演示了如何使用 Drizzle 和生成列在 PostgreSQL 中实现全文搜索。生成列是一个特殊的列,它总是从其他列计算得出。它的好处在于你不必每次查询表时都计算该列的值:
schema.ts
migration.sql
import { SQL, sql } from 'drizzle-orm';
import { index, pgTable, serial, text, customType } from 'drizzle-orm/pg-core';
export const tsvector = customType<{
data: string;
}>({
dataType() {
return `tsvector`;
},
});
export const posts = pgTable(
'posts',
{
id: serial('id').primaryKey(),
title: text('title').notNull(),
body: text('body').notNull(),
bodySearch: tsvector('body_search')
.notNull()
.generatedAlwaysAs((): SQL => sql`to_tsvector('english', ${posts.body})`),
},
(t) => [
index('idx_body_search').using('gin', t.bodySearch),
]
);
当你向表中插入一行时,生成列的值是从创建列时提供的表达式计算得出的:
import { posts } from './schema';
const db = drizzle(...);
const body = "金色的树叶覆盖了宁静的街道,清脆的微风充满空气,带来了雨的气息和变化的承诺"
await db.insert(posts).values({
body,
title: "秋天的美丽",
}
).returning();
[
{
id: 1,
title: '秋天的美丽',
body: '金色的树叶覆盖了宁静的街道,清脆的微风充满空气,带来了雨的气息和变化的承诺',
bodySearch: "'air':13 'breez':10 'bring':14 'chang':23 'cover':3 'crisp':9 'fill':11 'golden':1 'leav':2 'promis':21 'quiet':5 'rain':18 'scent':16 'street':6"
}
]
这就是如何通过生成列在 PostgreSQL 中使用 Drizzle ORM 实现全文搜索的方法。@@
操作符用于直接匹配:
const searchParam = "bring";
await db
.select()
.from(posts)
.where(sql`${posts.bodySearch} @@ to_tsquery('english', ${searchParam})`);
select * from posts where body_search @@ to_tsquery('english', 'bring');
这是一个更高级的模式,其中有一个生成列。search
列是由 title
和 body
列生成的,setweight()
函数用于为全文搜索分配不同的权重。这通常用于标记来自文档不同部分的条目,如标题与正文。
schema.ts
migration.sql
import { SQL, sql } from 'drizzle-orm';
import { index, pgTable, serial, text, customType } from 'drizzle-orm/pg-core';
export const tsvector = customType<{
data: string;
}>({
dataType() {
return `tsvector`;
},
});
export const posts = pgTable(
'posts',
{
id: serial('id').primaryKey(),
title: text('title').notNull(),
body: text('body').notNull(),
search: tsvector('search')
.notNull()
.generatedAlwaysAs(
(): SQL =>
sql`setweight(to_tsvector('english', ${posts.title}), 'A')
||
setweight(to_tsvector('english', ${posts.body}), 'B')`,
),
},
(t) => [
index('idx_search').using('gin', t.search),
],
);
这就是如何使用全文搜索查询表的方法:
const search = 'travel';
await db
.select()
.from(posts)
.where(sql`${posts.search} @@ to_tsquery('english', ${search})`);
select * from posts where search @@ to_tsquery('english', 'travel');