跳到主要内容
版本:3.0.0

标签组件

适用于 @midwayjs/faas@midwayjs/web@midwayjs/koa@midwayjs/express 多种框架的通用标签组件。

使用场景

标签是一种抽象化的服务端常用系统化能力,可用于多种用途,如:

  • 组织管理资源
    • 实现分类系统(面向内容、人群等)
    • 资源管理系统
      • 图片添加各种颜色标签、物体和场景标签,通过标签筛选图片
      • 视频等素材标签
  • 访问控制
    • 权限系统(管理员、编辑、游客)
  • 状态系统(编辑中、已发布等)

基于标签系统提供的增删改查,以及通过标签,对绑定了标签的 实体 进行增删改查,能够很方便的实现更多高级的业务逻辑。

标签系统就是为了这种业务场景,让服务端基于标签能力,实现更高效、便捷的业务开发。

相关信息:

web 支持情况
@midwayjs/koa
@midwayjs/faas
@midwayjs/web
@midwayjs/express

如何使用?

  1. 安装依赖
$ npm i @midwayjs/tags --save
  1. 在 configuration 中引入组件
// src/configuration.ts
import { Configuration } from '@midwayjs/core';
import * as tags from '@midwayjs/tags';
@Configuration({
imports: [
// ...
tags
],
})
export class MainConfiguration {}
  1. 添加配置
// src/config/config.local.ts
export default {
tags: {
clients: {
'tagGroup1': {
// 使用 本机内存 作为数据存储
dialectType: 'memory',
},
},
}
}
  1. 在代码中调用
// src/testTags.ts
import { Provide, Inject, InjectClient } from '@midwayjs/core';
import { TagServiceFactory, TagClient } from '@midwayjs/tags';
@Provide()
export class TestTagsService {
@Inject()
tags: TagServiceFactory;

// 相当于 this.tags.get('tagGroup1')
@InjectClient(TagServiceFactory, 'tagGroup1')
tagClient: TagClient;

@ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/tags/list', method: 'get'})
async listTags() {
// 也可以直接使用 this.tagClient
const tagClient: TagClient = this.tags.get('tagGroup1');
// add new tag
const tagInfo = await tagClient.new({
name: 'test-tag-name',
desc: 'tag desc',
});
/*
tagInfo = {
success: true,
id: 1,
}
*/
// list top 20 tags
const tags = await tagClient.list({ count: true });
/*
tags: {
list: [
{
id: 1,
name: 'test-tag-name',
desc: 'tag desc'
}
],
total: 1
}
*/
return tags;
}
}

方法

新增标签 new

new(tagDefine:  {
// 标签名,在同一个 group 里面不能重复
name: string;
// 标签描述
desc?: string;
}): Promise<{
success: boolean;
message: string;
// 标签id
id?: number;
}>;

删除标签 remove

删除标签也会删除和这个标签绑定的实体关系

remove(tagIdOrName: number | string): Promise<{
success: boolean;
message: string;
// 标签id
id?: number;
}>;

更新标签 update

更细一个标签的基础信息

update(tagIdOrName: number | string, params: Partial< {
name: string;
desc?: string;
}>): Promise<{
success: boolean;
message: string;
// 标签id
id?: number;
}>;

列举标签 list

搜索标签,支持分页

list(listOptions?: {
// 搜索的标签,支持传入标签 id 和标签名
tags?: Array<number | string>;
// 检索的时候标签是采用交集还是并集,取值为 and 和 or
type?: MATCH_TYPE;
count?: boolean;
pageSize?: number;
page?: number;
}): Promise<{
// 标签列表
list: {
id: number;
name: string;
desc: string;
createAt: number;
updateAt: number;
}[];
// 标签总数
total?: number;
}>;

绑定实体 bind

绑定实体的意思就是将其他的任何东西绑定到一个标签上,这里的实体可以是一张图片、也可以是一个文件,实体的id由用户自己控制

bind(bindOptions: {
// 标签列表
tags: Array<number | string>;
// 不存在标签的话自动创建标签,并绑定,默认为false
autoCreateTag?: boolean;
// 实体id
objectId: number,
}): Promise<{
success: boolean;
message: string;
}>

解绑实体 unbind

unbind(unbindOptions: {
// 解绑的多个标签,标签id或者是标签 name
tags: Array<number | string>,
// 实体id
objectId: number,
}): Promise<{
success: boolean;
message: string;
}>

根据标签列举实体 listObjects

listObjects(listOptions?: {
// 标签id或者是标签 name
tags?: Array<string|number>;
count?: boolean;
// 检索的时候标签是采用交集还是并集,取值为 and 和 or
type?: MATCH_TYPE;
pageSize?: number;
page?: number;
}): Promise<{
// 实体的 id 列表
list: number[];
// 实体总数
total?: number;
}>;

根据实体获取标签 listObjectTags

listObjectTags(listOptions?: {
// 实体id
objectId: number;
count?: boolean;
pageSize?: number;
page?: number;

}): Promise<{
list: { // 标签列表
name: string;
desc?: string;
id: number;
createAt: number;
updateAt: number;
}[];
// 标签总数
total?: number;
}>;

配置

Tags 支持内存存储(默认)和 mysql 数据库存储两种方式,下面是一个配置的示例:

// src/config/config.local.ts
export default {
tags: {
clients: {
'tagGroup1': {
// 使用 本机内存 作为数据存储
dialectType: 'memory',
},
'tagGroup2': {
// 使用 mysql 作为数据存储
dialectType: 'mysql',
// 自动同步表结构
sync: true,
// mysql 连接实例
instance: mysqlConnection.promise(),
},
},
}
}

内存存储配置

配置值类型默认值配置描述
dialectTypestring memory-配置为 memory,则启用内存存储

Mysql 存储配置

如果要使用 Mysql 数据库作为数据存储,那么需要将 Mysql 的 数据库连接对象 传入 tags 的配置中。

配置值类型默认值配置描述
dialectTypestring mysql-配置为 mysql,则启用 Mysql 存储
syncbooleanfalse自动同步 Tags 的表结构,Tags组件会创建两张数据表,详见下方的数据表信息
instance{ query: (sql: string, placeholder?: any[])}: Promise<[]>-Mysql 连接的示例,需要提供一个 query 方法,可以查看下面的示例
tablePrefixstring-数据表前缀
tableSeparatorstring_数据表的拼接分隔符

下面是使用 mysql2 这个 npm 包进行数据库连接的示例:

// src/config/config.local.ts
const mysql = require('mysql2');
export default () => {
const connection = mysql.createConnection({
host: 'db4free.net',
user: 'tag***',
password: 'tag***',
database: 'tag***',
charset: 'utf8',
});
return {
tags: {
clients: {
'tagGroup': {
dialectType: 'mysql',
sync: true,
instance: { // 包含 query 的mysql连接实例
query: (...args) => {
return connection.promise().query(...args);
}
},
},
},
}
}
}

你也可以考虑在 configuration.ts 中的 onConfigLoad 生命周期中进行数据库连接,这样的好处是在关闭时,可以关闭数据库连接:

// src/configuration.ts
import { Config, Configuration } from '@midwayjs/core';
import { join } from 'path';
import * as tags from '@midwayjs/tags';
import { ITagMysqlDialectOption } from '@midwayjs/tags';
const mysql = require('mysql2');

@Configuration({
imports: [
tags
],
})
export class MainConfiguration {
connection;

@Config()
tags;

async onConfigLoad(container) {
// 创建 mysql 连接
this.connection = mysql.createConnection({
host: 'db4free.net',
user: 'tag***',
password: 'tag***',
database: 'tag***',
charset: 'utf8',
});
let dialect: ITagMysqlDialectOption = {
dialectType: 'mysql',
sync: true,
instance: {
query: (...args) => {
return this.connection.promise().query(...args);
}
}
};

return {
tags: dialect
}
}

async onStop() {
// 关闭 mysql 连接
this.connection.close();
}
}

数据表信息

Tags 组件需要两种数据表来存储数据,分别是 tagrelationship,这两张表在数据库中真实的表名,是通过配置中的 表名前缀表名分隔符客户端名/分组名 进行拼接的,例如:

const clientName = 'local-test';
const { tablePrefix = 'a', tableSeparator = '_' } = tagOptions;
const tagTableName = `${tablePrefix}${tableSeparator}${clientName}${tableSeparator}tag`;
// tagTableName: a_local-test_tag
const relationshipTableName = `${tablePrefix}${tableSeparator}${clientName}${tableSeparator}relationship`
// relationshipTableName: a_local-test-relationship

当你在配置中启用 sync 的自动表结构同步时,如果没有这两张表,就会根据下述的表结构创建对应的数据表:

tag 表结构:

CREATE TABLE `tag` (
`id` BIGINT unsigned NOT NULL AUTO_INCREMENT,
`group` varchar(32) NULL,
`name` varchar(32) NULL,
`descri` varchar(128) NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
`update_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id)
)

relationship 表结构:

CREATE TABLE `relationship` (
`id` BIGINT unsigned NOT NULL AUTO_INCREMENT,
`tid` BIGINT unsigned NOT NULL,
`oid` BIGINT unsigned NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
`update_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id)
)