node.js项目使用sequelize处理多对多模型的时候,如何实现数据的增删改查问题。

需求分析:
一篇文章可以有多个标签tag,一个标签也可以属于多个文章。
文章article模型和标签tag模型,属于多对多关系。

1、模型定义:

文章模型

const {Tag} = require('./tag')
// 定义文章模型
class Article extends Model {

}

// 初始文章模型
Article.init({
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  title: {
    type: Sequelize.STRING(50),
    allowNull: false,
    comment: '文章标题'
  },
  author: {
    type: Sequelize.STRING(30),
    allowNull: true,
    defaultValue: 'Admin',
    comment: '文章作者'
  },
  content: {
    type: Sequelize.TEXT,
    allowNull: false,
    comment: '文章内容'
  },
  description: {
    type: Sequelize.STRING,
    allowNull: false,
    comment: '文章简介'
  },
  created_at: {
    type: Sequelize.DATE,
    allowNull: false
  }
}, {
  sequelize,
  modelName: 'article',
  tableName: 'article'
})
// 重点:多对多模型关联
Article.belongsToMany(Tag, { through: "ArticleTag"
})
Tag.belongsToMany(Article, { through: "ArticleTag"
})
module.exports = {
  Article
}

tag标签模型

// 定义文章模型
class Tag extends Model {
}

// 初始分类模型
Tag.init({
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  name: {
    type: Sequelize.STRING,
    allowNull: false,
    comment: 'tag名称'
  },
  remark: {
    type: Sequelize.STRING,
    allowNull: true,
    comment: '备注'
  },
  created_at: {
    type: Sequelize.DATE,
    allowNull: false,
  }
}, {
  sequelize,
  modelName: 'tag',
  tableName: 'tag'
})

module.exports = {
  Tag
}

注意,在文章模型内部,使用了belongsToMany来关联tag模型,通过ArticleTag会自动生成第三张表。

在Dao层处理文章新增的时候

// 引入xss攻击预防包
const xss = require('xss')
// op模块,进行关键字搜索
const { Op } = require('sequelize')

const { Article } = require('../../models/blog/article')
const { Category } = require('../../models/blog/category')
const { Tag } = require('../../models/blog/tag')

// 定义文章模型
class ArticleDao {

  // 创建文章
  static async create(v) {

    // 检测是否存在文章
    const hasArticle = await Article.findOne({
      where: {
        title: v.get('body.title'),
        deleted_at: null
      }
    });

    // 如果存在,抛出存在信息
    if (hasArticle) {
      throw new global.errs.Existing('文章已存在');
    }

    // 可行方式一:
    // let title = v.get('body.title')
    // let author = v.get('body.author')
    // let keyword = v.get('body.keyword')
    // let description = v.get('body.description')
    // let content = v.get('body.content')
    // let cover = v.get('body.cover')
    // let category_id = v.get('body.category_id')
    // let tags = v.get('body.tags')
    // let a = {
    //   title: title,
    //   author: author,
    //   keyword: keyword,
    //   description: description,
    //   content: content,
    //   cover: cover,
    //   category_id: category_id,
    // }
    // Article.create(a).then((article) => {
    //   Tag.findAll({where: {id: tags}}).then((tags) => {
    //     article.setTags(tags)
    //     return {message: "添加成功"}
    //   })
    // })

	// 可行方式二:
    let title = v.get('body.title')
    let author = v.get('body.author')
    let keyword = v.get('body.keyword')
    let description = v.get('body.description')
    let content = v.get('body.content')
    let cover = v.get('body.cover')
    let category_id = v.get('body.category_id')
    let tagsIds = v.get('body.tags')
    let a = {
      title: title,
      author: author,
      keyword: keyword,
      description: description,
      content: content,
      cover: cover,
      category_id: category_id,
    }

    let article = await Article.create(a)
    if (tagsIds && tagsIds.length) {
      let tags = await Tag.findAll({ where: { id: tagsIds } })
      article.setTags(tags)
    }

    return article


    // 创建文章
    // const article = new Article();

    // article.title = v.get('body.title');
    // article.author = v.get('body.author');
    // article.keyword = v.get('body.keyword');
    // article.description = v.get('body.description');
    // article.content = xss(v.get('body.content'));
    // article.cover = v.get('body.cover');
    // article.browse = v.get('body.browse');
    // article.category_id = v.get('body.category_id');

    // article.save();
  }

}

module.exports = {
  ArticleDao
}

原理就是,通过Article模型的create方法会在Article文章模型中新增一条文章数据,然后通过传递的tag标签数组,在标签Tag表中查询出tags标签列表,然后通过创建的文章article实例上的setTags方法,在第三张中间表中添加关联数据。
在这里插入图片描述

这个地方,我想了好半天,差点感觉不行,自己人为的去控制第三张关联表的数据。也找了很多地方,摸索出来的这个方法。

自己记录,也希望能够帮助到在使用Node.js中可能遇到同样问题的朋友。

简介表述:

 dbModels.article.create({
        title: req.body.title,
        auhor: req.body.auhor
    }).then(function (code) {
        dbModels.tag.findAll({where: {id: req.body.tags}}).then(function (tags) {
            article.setTags(tags)
            return res.status(200).json({
                message:'添加文章成功'
            })
        })
    })

就是这个给了我思路。先创建文章,然后通过标签id数组tags在tag模型中查询到符合条件的标签数据,然后再通过保存的文章实例上的setTags方法,将关联的数据保存到第三张模型articletag中间表中去的,而不是自己手动的去这个第三张中间表存数据。

2、查询文章详情时关联tag标签

通过include来进行关联查询。

  // 文章详情
  static async detail(id) {
    const article = await Article.findOne({
      where: {
        id
      },
      // 查询每篇文章下关联的分类和标签
      include: [{
        model: Category,
        as: 'category',
        attributes: {
          exclude: ['deleted_at', 'updated_at']
        }
      },
      {
        model: Tag,
        attributes: ['id', 'name']
      }
    ]
    });
    if (!article) {
      throw new global.errs.NotFound('没有找到相关文章');
    }
    return article;
  }

返回结果

{
  "code": 200,
  "msg": "success",
  "errorCode": 0,
  "data": {
    "created_at": "2020-06-16",
    "id": 18,
    "title": "Systemic racism a",
    "author": "Admin",
    "content": "<p>Some form of restricted zone encompassing 60 million people in the United States would cover all the citizens in California, Washington, Oregon, Nevada, and Arizona combined—or an entire swath of the country directly to the east of those western states. </p><p>The sweeping measures in Italy and Hubei province are focused on severely restricting travel first and foremost. The restrictions vary but are geared toward keeping people in their homes and avoiding movement as much as possible. Public transport, from buses to planes and trains, has been curtailed or, in some cases, shut down entirely. Highways might be manned by checkpoints. Italians, for example, must get official permission if they need to travel within the country for work, health, or any other significant purpose. Schools are closed as are businesses, except those considered essential, such as grocery stores and pharmacies. “Social distancing” measures include businesses that are allowed to stay open enforcing a three-foot distance between customers. China’s clampdown began January 23 and quickly widened throughout Hubei province, as the number of cases has been falling there. Italy’s countrywide limits, announced March 9, came as regional restrictions failed to stem the contagion and health systems became increasingly strained. </p>",
    "description": "Two massive lockdowns are already under way—the entire country of Italy and China’s Hubei province, both home to some 60 million people.",
    "keyword": "coronavirus",
    "cover": "image/blog-12.jpg",
    "browse": 1,
    "updated_at": "2020-06-16T01:15:13.000Z",
    "deleted_at": null,
    "category_id": 4,
    "category": {
      "created_at": "2020-06-11",
      "id": 4,
      "name": "News",
      "keyword": "News",
      "parent_id": 0,
      "remark": ""
    },
    "tags": [
      {
        "id": 1,
        "name": "Life",
        "ArticleTag": {
          "created_at": "2020-06-16T01:15:14.000Z",
          "updated_at": "2020-06-16T01:15:14.000Z",
          "articleId": 18,
          "tagId": 1
        }
      },
      {
        "id": 2,
        "name": "Vue",
        "ArticleTag": {
          "created_at": "2020-06-16T01:15:14.000Z",
          "updated_at": "2020-06-16T01:15:14.000Z",
          "articleId": 18,
          "tagId": 2
        }
      }
    ],
    "article_comment": {
      "data": [],
      "meta": {
        "current_page": 1,
        "per_page": 10,
        "count": 0,
        "total": 0,
        "total_pages": 0
      }
    }
  }
}

3.文章列表查询关联tag标签

在列表查询,使用through来关联查询tag标签

4、通过tag标签来筛选查询对应的文章

这里又是一个坑,想来找去,没有找到答案。
一直以为,这个地方应该是在article文章路由中来实现。实际上,这里,需要在tag标签路由中来实现。
如果有大哥知道,更正确的方法,麻烦告知一下。

  // 通过tag标签获取关联文章列表
  static async ArticleDetail(id) {
    const tag = await Tag.scope('bh').findOne({
      where: {
        id,
        deleted_at: null
      }
    });
    if (!tag) {
      throw new global.errs.NotFound('没有找到相关tag');
    }
    const all = await Tag.findAll({
      where: {
        id: id
      },
      include: [
        {
          model: Article
        }
      ]
    })
    return all
  }

这里,通过传入的tag标签,查询到tag后,使用include的关联技术,把关联的文章查询出来。

返回结果

{
  "code": 200,
  "msg": "success",
  "errorCode": 0,
  "data": [
    {
      "created_at": "2020-06-16",
      "id": 2,
      "name": "Vue",
      "remark": null,
      "updated_at": "2020-06-16T00:58:50.000Z",
      "deleted_at": null,
      "articles": [
        {
          "created_at": "2020-06-16",
          "id": 18,
          "title": "Systemic racism a",
          "author": "Admin",
          "content": "<p>Some form of restricted zone encompassing 60 million people in the United States would cover all the citizens in California, Washington, Oregon, Nevada, and Arizona combined—or an entire swath of the country directly to the east of those western states. </p><p>The sweeping measures in Italy and Hubei province are focused on severely restricting travel first and foremost. The restrictions vary but are geared toward keeping people in their homes and avoiding movement as much as possible. Public transport, from buses to planes and trains, has been curtailed or, in some cases, shut down entirely. Highways might be manned by checkpoints. Italians, for example, must get official permission if they need to travel within the country for work, health, or any other significant purpose. Schools are closed as are businesses, except those considered essential, such as grocery stores and pharmacies. “Social distancing” measures include businesses that are allowed to stay open enforcing a three-foot distance between customers. China’s clampdown began January 23 and quickly widened throughout Hubei province, as the number of cases has been falling there. Italy’s countrywide limits, announced March 9, came as regional restrictions failed to stem the contagion and health systems became increasingly strained. </p>",
          "description": "Two massive lockdowns are already under way—the entire country of Italy and China’s Hubei province, both home to some 60 million people.",
          "keyword": "coronavirus",
          "cover": "image/blog-12.jpg",
          "browse": 1,
          "updated_at": "2020-06-16T03:08:18.000Z",
          "deleted_at": null,
          "category_id": 4,
          "ArticleTag": {
            "created_at": "2020-06-16T01:15:14.000Z",
            "updated_at": "2020-06-16T01:15:14.000Z",
            "articleId": 18,
            "tagId": 2
          }
        },
        {
          "created_at": "2020-06-16",
          "id": 20,
          "title": "Systemic racism c",
          "author": "Admin",
          "content": "<p>Some form of restricted zone encompassing 60 million people in the United States would cover all the citizens in California, Washington, Oregon, Nevada, and Arizona combined—or an entire swath of the country directly to the east of those western states. </p><p>The sweeping measures in Italy and Hubei province are focused on severely restricting travel first and foremost. The restrictions vary but are geared toward keeping people in their homes and avoiding movement as much as possible. Public transport, from buses to planes and trains, has been curtailed or, in some cases, shut down entirely. Highways might be manned by checkpoints. Italians, for example, must get official permission if they need to travel within the country for work, health, or any other significant purpose. Schools are closed as are businesses, except those considered essential, such as grocery stores and pharmacies. “Social distancing” measures include businesses that are allowed to stay open enforcing a three-foot distance between customers. China’s clampdown began January 23 and quickly widened throughout Hubei province, as the number of cases has been falling there. Italy’s countrywide limits, announced March 9, came as regional restrictions failed to stem the contagion and health systems became increasingly strained. </p>",
          "description": "Two massive lockdowns are already under way—the entire country of Italy and China’s Hubei province, both home to some 60 million people.",
          "keyword": "coronavirus",
          "cover": "image/blog-12.jpg",
          "browse": 0,
          "updated_at": "2020-06-16T02:02:26.000Z",
          "deleted_at": null,
          "category_id": 4,
          "ArticleTag": {
            "created_at": "2020-06-16T02:02:26.000Z",
            "updated_at": "2020-06-16T02:02:26.000Z",
            "articleId": 20,
            "tagId": 2
          }
        }
      ]
    }
  ]
}

5、通过文章更新来更新tag标签

  // 更新文章
  static async update(id, v) {
    // // 查询文章
    const article = await Article.findByPk(id);
    if (!article) {
      throw new global.errs.NotFound("没有找到相关文章");
    }

    let tagsIds = v.get("body.tags");
    let a = {};
    if (v.get("body.title")) {
      a.title = v.get("body.title");
    }
    if (v.get("body.author")) {
      a.author = v.get("body.author");
    }
    if (v.get("body.keyword")) {
      a.keyword = v.get("body.keyword");
    }
    if (v.get("body.description")) {
      a.description = v.get("body.description");
    }
    if (v.get("body.content")) {
      a.content = xss(v.get("body.content"));
    }
    if (v.get("body.cover")) {
      a.cover = v.get("body.cover");
    }
    if (v.get("body.browse")) {
      a.browse = v.get("body.browse");
    }
    if (v.get("body.category_id")) {
      a.category_id = v.get("body.category_id");
    }
    article.update(a);
    if (tagsIds && tagsIds.length) {
      let tags = await Tag.findAll({ where: { id: tagsIds } });
      article.setTags(tags);
    }
}

我尝试,只能通过先update文章,再使用setTags来更新tag,使用实例save(),这种形式,不行。

猜你喜欢

转载自blog.csdn.net/qq_42991509/article/details/106782215