亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > PostgreSQL > 正文

PostgreSQL實現一個通用標簽系統

2020-01-31 15:20:54
字體:
來源:轉載
供稿:網友

前言

對資源打標簽在建站過程中是很常見的需求,有些時候我們需要給文章打標簽,有些時候我們需要給用戶打標簽。實現一個標簽系統其實并不難,其本質就是一個多對多的關系-我可以對同一篇博客打多個標簽,同時也可以把一個標簽打到不同的博客身上。這篇文章主要通過分析標簽系統的原理,并用PostgreSQL來實現一個能夠為多種資源打標簽的標簽系統。

1. 單一資源標簽系統

先從單一資源開始,所謂單一資源便是,我們只給一種數據資源打標簽。假設我們需要給博客文章打標簽,那么我們需要構建以下幾個表:

  • 文章表posts,用于存儲文章的基本信息。
  • 標簽表tags,用于存儲標簽的基本信息。
  • 標簽-文章表tags_posts,存儲雙方的id并形成多對多的關系。

表設計圖大概是

先進入數據庫引擎并創建對應的數據庫

postgres=# create database blog;CREATE DATABASEpostgres=# /c blog;blog=#

通過SQL語句創建上面所提到的數據表

CREATE TABLE posts ( id    SERIAL, body   text, title   varchar(80));CREATE TABLE tags ( id    SERIAL, name   varchar(80));CREATE TABLE tags_posts ( id    SERIAL, tag_id   integer, post_id   integer);

每個表都只是包含了該資源最基礎的字段, 到這一步為止其實已經構建好了一個最簡單的標簽系統了。接下來則是填充數據,我的策略是添加兩篇文章,五個標簽,給標題為Ruby的文章打上language標簽,給標題為Docker的文章打上container的標簽,兩篇文章都要打上tech標簽

-- 填充文章數據INSERT INTO posts (body, title) VALUES ('Hello Ruby', 'Ruby');INSERT INTO posts (body, title) VALUES ('Hello Docker', 'Docker');-- 填充標簽數據INSERT INTO tags (name) VALUES ('language');INSERT INTO tags (name) VALUES ('container');INSERT INTO tags (name) VALUES ('tech');-- 為相關資源打上標簽INSERT INTO tags_posts (tag_id, post_id) VALUES ((SELECT id FROM tags WHERE name = 'container'), (SELECT id FROM posts WHERE title = 'Docker'));INSERT INTO tags_posts (tag_id, post_id) VALUES ((SELECT id FROM tags WHERE name = 'tech'), (SELECT id FROM posts WHERE title = 'Docker'));INSERT INTO tags_posts (tag_id, post_id) VALUES ((SELECT id FROM tags WHERE name = 'tech'), (SELECT id FROM posts WHERE title = 'Ruby'));INSERT INTO tags_posts (tag_id, post_id) VALUES ((SELECT id FROM tags WHERE name = 'language'), (SELECT id FROM posts WHERE title = 'Ruby'));

然后分別查詢兩篇文章都被打上了什么標簽。

blog=# SELECT tags.name FROM tags, posts, tags_posts WHERE tags.id = tags_posts.tag_id AND posts.id = tags_posts.post_id AND posts.title = 'Ruby'; name---------- language tech(2 rows)blog=# SELECT tags.name FROM tags, posts, tags_posts WHERE tags.id = tags_posts.tag_id AND posts.id = tags_posts.post_id AND posts.title = 'Docker'; name----------- container tech(2 rows)

兩篇文章都被打上期望的標簽了,相關的語句有點長,一般生產線上不會這樣直接操作數據庫。各種編程語言的社區一般都對這種數據庫操作進行了封裝,這為編寫業務代碼帶來了不少的便利性。

2. 為多種資源打標簽

如果只需要對一個數據表打標簽的話,依照上面的邏輯來設計表已經足夠了。但是現實世界往往沒那么簡單,假設除了要給博客文章打標簽之外,還需要給用戶表打標簽呢?我們需要把表設計得更靈活一些。如果繼續用tags表來存標簽數據,為了給用戶打標簽還得另外建一個名為tags_users的表來存儲標簽與用戶數據之間的關系。

但更好的做法應該是采用名為多態的設計。創建關聯表taggings,這個關聯表除了會存儲關聯的兩個id之外,還會存儲被打上標簽的資源類型,我們根據類型來區分被打標簽的到底是哪種資源,這會在每條記錄上多存了類型數據,不過好處就是可以少建表,所有的標簽關系都通過一個表來存儲。

Ruby比較流行的標簽系統ActsAsTaggableOn 就沿用了這個設計,不過它的類型字段直接存的是對應資源的類名,或許是為了更方便編程吧,數據大概如下:

naive_development=# select id, tag_id, taggable_type, taggable_id from taggings; id | tag_id | taggable_type  | taggable_id----+--------+----------------------+------------- 1 |  1 | Refinery::Blog::Post |   1 2 |  2 | Refinery::Blog::Post |   1 3 |  3 | Refinery::Blog::Post |   1

先通過taggable_type獲取類名,然后再利用taggable_id的數據就能準確獲取相關的資源了。

a. 修改原表

表設計圖大概如下

這里我不重新建表了,而直接修改原有的表,并進行數據遷移

  • 增加type字段用于存儲資源類型。
  • 把原來的數據表改名為更通用的名字taggings。
  • 把原來的post_id字段改成更通用的名字taggable_id。
  • 給原有的資源填充數據,type字段統一填數據post。
ALTER TABLE tags_posts ADD COLUMN type varchar(80);ALTER TABLE tags_posts RENAME TO taggings;ALTER TABLE taggings RENAME COLUMN post_id TO taggable_id;UPDATE taggings SET type='post';

b. 添加用戶

在給用戶打標簽之前先創建用戶表,并填充數據

-- 創建簡單的用戶表CREATE TABLE users ( id    SERIAL, username  varchar(80), age    integer);-- 添加一個名為lan的用戶,并添加兩個相關的標簽INSERT INTO users (username, age) values ('lan', 26);INSERT INTO tags (name) VALUES ('student');INSERT INTO tags (name) VALUES ('programmer');

c. 給用戶打標簽

接下來需要給用戶lan打上標簽,對原有的SQL語句做一些調整,并在打標簽的時候把type字段填充為user。

INSERT INTO taggings (tag_id, taggable_id, type) VALUES ((SELECT id FROM tags WHERE name = 'student'), (SELECT id FROM users WHERE username = 'lan'), 'user');INSERT INTO taggings (tag_id, taggable_id, type) VALUES ((SELECT id FROM tags WHERE name = 'programmer'), (SELECT id FROM users WHERE username = 'lan'), 'user');

上述的SQL語句為用戶打上了student以及programmer兩個標簽。

d. 查看標簽情況

為了完成這個任務我們依然要聯合三張表進行查詢,同時還要約束type的類型

用戶名為lan的用戶被打上的所有標簽

blog=# SELECT tags.name FROM tags, users, taggings WHERE tags.id = taggings.tag_id AND users.id = taggings.taggable_id AND taggings.type = 'user' AND users.username = 'lan'; name------------ student programmer(2 rows)

標題為Ruby的文章被打上的所有標簽

blog=# SELECT tags.name FROM tags, posts, taggings WHERE tags.id = taggings.tag_id AND posts.id = taggings.taggable_id AND taggings.type = 'post' AND posts.title = 'Ruby'; name---------- language tech

OK,都跟預期一樣,現在的標簽系統就比較通用了。

總結

本文通過PostgreSQL的基礎語句來構建了一個標簽系統。實現了一個標簽系統其實并不難,各個語言的社區應該都有相關的集成。本人也就是想拋開編程語言,從數據庫層面來剖析一個標簽系統的基本原理。

PS: 另外推薦一個比較好用的Model Design工具dbdiagram,可以用文本的方式對數據表進行設計,邊設計邊預覽。最后還能以PNG,PDF甚至SQL源文件的形式導出。本文的數據表配圖均由用該軟件制作。

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91av在线网站| 久久伊人色综合| 91探花福利精品国产自产在线| 国产欧美欧洲在线观看| 国内精品伊人久久| 欧美午夜宅男影院在线观看| 久久久久久国产精品美女| 久久精品国产电影| 国产精品极品美女在线观看免费| 深夜福利日韩在线看| 日本一区二区在线播放| 国产日韩av高清| 亚洲2020天天堂在线观看| 91精品国产高清自在线| 日韩欧亚中文在线| 久久精品亚洲国产| 国产精品久久久久久亚洲影视| 国产精品扒开腿做爽爽爽视频| 欧美性猛交xxxx免费看| 在线观看日韩www视频免费| 亚洲三级 欧美三级| 国产欧美日韩免费看aⅴ视频| 国产一区二区三区网站| 欧美视频一二三| 国产视频一区在线| 欧美一级大胆视频| 久久视频在线看| 在线播放亚洲激情| 欧美日韩国产中文字幕| 日韩av色在线| 欧美在线观看日本一区| 国产成人免费av电影| 韩剧1988免费观看全集| 欧洲成人在线视频| 一区二区三区国产视频| 中文字幕久热精品在线视频| 亚洲欧洲高清在线| 亚洲最大成人网色| 国产精品美女视频网站| 97视频免费在线看| 91热福利电影| 97视频在线观看免费| 精品中文字幕在线| 欧美激情在线观看视频| 久久影视电视剧免费网站| 色综久久综合桃花网| 欧美日韩亚洲精品一区二区三区| 亚洲人成在线播放| 亚洲成人黄色网| 亚洲无亚洲人成网站77777| 久久久999成人| 欧美日韩精品在线视频| 91国产中文字幕| 成人免费在线视频网站| 亚洲欧美精品一区二区| 欧洲精品在线视频| 久久99久国产精品黄毛片入口| 精品久久久久久亚洲国产300| 亚洲欧美精品一区二区| 国产成人精品久久二区二区| 日韩美女av在线免费观看| 91丨九色丨国产在线| 欧美性猛交xxxxx免费看| 亚洲第一色中文字幕| 亚洲毛片在线看| 亚洲国产欧美在线成人app| 国产精品揄拍500视频| 国产精品中文字幕在线观看| 欧美肥婆姓交大片| 国产精品自拍视频| 国产成人精品综合久久久| 大伊人狠狠躁夜夜躁av一区| 97在线观看免费| 国产精品亚洲网站| 8050国产精品久久久久久| 日韩动漫免费观看电视剧高清| 欧美成人免费全部观看天天性色| 69国产精品成人在线播放| 全色精品综合影院| 日韩av免费在线| 亚洲另类欧美自拍| 午夜精品久久久久久久白皮肤| 亚洲第一页中文字幕| 久久亚洲春色中文字幕| 日韩暖暖在线视频| 国产91精品网站| 国产午夜精品视频免费不卡69堂| 午夜精品一区二区三区视频免费看| 欧美猛男性生活免费| 欧洲一区二区视频| 国产精品直播网红| 57pao国产成人免费| 国产69久久精品成人| 久久99久久99精品中文字幕| 亚洲码在线观看| 亚洲第一综合天堂另类专| 欧美精品久久久久a| 日韩精品小视频| 69久久夜色精品国产69| 久久精品夜夜夜夜夜久久| 国产亚洲欧美aaaa| 亚洲人成网站色ww在线| 2018中文字幕一区二区三区| 国产精品久久99久久| 国产精品狼人色视频一区| 亚洲性av在线| 国外成人在线视频| 日韩视频精品在线| 亚洲男人天堂2019| 国产在线观看精品一区二区三区| 性欧美激情精品| 亚洲精品中文字幕有码专区| 亚洲精品国产拍免费91在线| 久久亚洲影音av资源网| 亚洲精品99久久久久中文字幕| 欧美性少妇18aaaa视频| 欧美性一区二区三区| 日韩av一区二区在线| 久久99热这里只有精品国产| 欧洲亚洲在线视频| 亚洲成在人线av| 欧美成年人视频网站欧美| 亚洲专区中文字幕| 欧美高清在线观看| 欧美成人高清视频| 日韩av一区在线观看| 久久久视频免费观看| 91探花福利精品国产自产在线| 欧美日韩综合视频网址| 中文字幕亚洲二区| 国产视频观看一区| 成人激情视频在线播放| 伊人精品在线观看| 亚洲色图激情小说| 亚洲第一偷拍网| 亚洲男人第一av网站| 久久久久久久久爱| 国产亚洲精品久久久久久牛牛| 亚洲自拍在线观看| 欧美又大粗又爽又黄大片视频| 国产欧美精品xxxx另类| 少妇激情综合网| 亚洲欧美综合另类中字| 亚洲free嫩bbb| 欧美综合激情网| 欧美孕妇毛茸茸xxxx| 91人人爽人人爽人人精88v| 国产精品久久久久久久久粉嫩av| 亚洲综合视频1区| 亚洲国产精品久久久久秋霞蜜臀| 久久精品99久久久香蕉| 最新的欧美黄色| 欧美日韩美女视频| 久久天天躁日日躁| 97人人模人人爽人人喊中文字| 亚洲国产精品免费| 欧美亚洲视频在线看网址| 色综合色综合网色综合| 国产精品日韩av| 伊人一区二区三区久久精品| 亚洲精品中文字幕有码专区| 国产欧美精品一区二区三区介绍| 久久久久久网址| 国产精品国产自产拍高清av水多|