🦄 2024 独立开发者训练营,一起创业!查看介绍 / 立即报名(剩余10个优惠名额) →

NNC D12:标签

D12 要做的训练内容是去创建一个标签模块,标签在应用里也是一种实体,每个标签可以有自己的名字、别名等等,你也可以加上标签的描述、缩略图之类的东西。

这次训练的重点是要理解多对多的关系,我们可以在每个文章内容上面打上多个标签,每个标签都可以关联一组文章内容。

先在标签实体上定义它跟文章内容的关系:

  @ManyToMany(type => Post, post => post.tags)
  posts: Post[];

标签上的这个关系的名字叫 posts,它的类型是一组 Post 实体。在 Post 实体上对应的关系应该叫 tags 。

在文章内容实体上定义与标签的关系:

  @ManyToMany(type => Tag, tag => tag.posts)
  @JoinTable()
  tags: Tag[];

同样使用 @ManyToMany 这个装饰器去定义多对多的关系,这个关系的名字叫 tags,类型是一组 Tag 实体。注意这里定义关系的时候用了一个 @JoinTable 装饰器,它可以创建一个中间表来保存内容与标签之间的多对多的关系。

发布或更新内容时存储与标签的关系

在发布或更新文章内容的时候,可以存储一下内容与标签之间的关系。我们需要改进内容服务上的两个方法:

src/modules/post/post.service.ts

async store(data: PostDto, user: User) {
    const { tags } = data;

    if (tags) {
      data.tags = await this.beforeTag(tags);
    }

    const entity = await this.postRepository.create(data);
    await this.postRepository.save({
      ...entity,
      user
    });
    return entity;
  }
 async update(id: string, data: Partial) {
    const { tags } = data;
    delete data.tags;

    await this.postRepository.update(id, data);

    const entity = await this.postRepository
      .findOne(id, { relations: ['category', 'tags'] });

    if (tags) {
      entity.tags = await this.beforeTag(tags);
    }

    return await this.postRepository.save(entity);
  }
  async beforeTag(tags: Partial[]) {
    const _tags = tags.map(async item => {
      const { id, name } = item;
      if (id) {
        const _tag = await this.tagRepository.findOne(id);

        if (_tag) {
          return _tag;
        }

        return;
      }

      if (name) {
        const _tag = await this.tagRepository.findOne({ name });

        if (_tag) {
          return _tag;
        }

        return await this.tagRepository.save(item);
      }
    });

    return Promise.all(_tags);
  }

在发布或更新内容的时候,存储内容与标签的关系,用了一个帮手方法叫 beforeTag,这个方法的作用是按标签的 id 找到对应的标签实体。如果打标签的时候提供的是标签的名字,就按名字去查找对应的标签实体,如果没找到就去创建一个同样名字的标签,最终方法返回需要给内容打上的所有标签实体。发布与更新内容用的方法会利用返回的这组标签实体,存储内容与标签之间的关系。

利用内容与标签的关系

比如在查询内容列表的时候,可以在地址的查询参数里提供一组标签,对应的服务方法可以得到这组标签内容,用它们作为查询文章列表时的一个查询条件。

 async index(options: ListOptionsInterface) {
    const { categories, tags } = options;
    const queryBuilder = await this.postRepository
      .createQueryBuilder('post');

    queryBuilder.leftJoinAndSelect('post.user', 'user');
    queryBuilder.leftJoinAndSelect('post.category', 'category');
    queryBuilder.leftJoinAndSelect('post.tags', 'tag');

    if (categories) {
      queryBuilder.where('category.alias IN (:...categories)', { categories });
    }

    if (tags) {
      queryBuilder.andWhere('tag.name In (:...tags)', { tags });
    }

    const entities = queryBuilder.getMany();
    return entities;
  }
微信好友

用微信扫描二维码,
加我好友。

微信公众号

用微信扫描二维码,
订阅宁皓网公众号。

240746680

用 QQ 扫描二维码,
加入宁皓网 QQ 群。

统计

15260
分钟
0
你学会了
0%
完成

社会化网络

关于

微信订阅号

扫描微信二维码关注宁皓网,每天进步一点