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
          }
        }
      ]
    }
  ]
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章