iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 23
1

昨天不僅完成了 Vuex Module Registration,
也完成了串接 Firebase 登入/登出/自動登入。

今天來建立部落格所有需要的資料庫結構,簡單分為兩個 vuex modules:

  • store/modules/tags.js
  • store/modules/post.js

store/modules/tags.js

tags 這個 module 的內容只有一個 action,
就是 getAllTags,直接來看程式碼:

import { db } from '@/services/fireinit'
import { uniq, flatten } from 'lodash'

export const actions = {
  getAllTags () {
    let postsCol = db.collection('posts').where('isShow', '==', true)
    return postsCol.orderBy('postTime', 'desc').get()
      .then(({ docs }) => {
        let allTags = []
        docs.forEach(doc => {
          allTags.push(doc.data().tags)
        })
        allTags = uniq(flatten(allTags))
        const promises = allTags.map(tag => {
          return postsCol.where('tags', 'array-contains', tag).get()
            .then(({ docs }) => {
              return {
                name: tag,
                size: docs.length,
              }
            })
        })
        return Promise.all(promises)
      })
  }
}

上面第一行可以看到:

import { db } from '@/services/fireinit'

fireinit 是前天寫好的套件,將 firestore export 為 db
這樣就可以透過 db 與 firestore 溝通(存、取、修改、刪除)。

第二行看到:

import { uniq, flatten } from 'lodash'

用到了 lodash 的 uniqflatten

action: getAllTags

從所有的文章中取出 tags, 並且透過 flatten 和 uniq 移除重複的部分。

store/modules/post.js

post 有 7 個 actions:

  • 部落格作者

    • addPost: 新增一篇文章
    • setPost: 修改一篇文章
    • getPostsAdmin: 取得 Admin 的文章列表(包含隱藏的文章)
  • 使用者

    • getPostsByPage: 取得某一頁的文章列表
    • getPostsTag: 取得某一個標籤的所有文章
    • getPostByPostId: 取得某一篇文章的內容
    • getPosts: 取得所有文章列表

由於這個 module 的程式碼較多,這邊就以 action 來分別介紹:

Action: addPost(新增一篇文章)

使用 db.collection('posts').add 新增文章,
成功回傳的 data 會自帶 data.id 作為辨別一篇文章的 postId。
而這個 action 會在元件 FormAddPost 被用到。

addPost ({}, payload) {
	return db.collection('posts').add({ ...payload })
		.then(data => ({ id: data.id, ...payload }))
}

Action: setPost(修改一篇文章)

修改一篇文章首先需要該篇文章的 postId,
這邊透過 set 並帶入參數 merge: true 自動合併。
而這個 action 會在元件 FormAddPost 被用到。

setPost ({}, payload) {
	return db.collection('posts').doc(payload.postId).set({ ...payload.thePost }, { merge: true })
		.then(() => ({ ...payload.thePost, id: payload.postId }))
}

Action: getPostsAdmin(取得 Admin 的文章列表)

列出所有文章,並用 orderBy('postTime', 'desc) 按照發布時間排序。

getPostsAdmin () {
	return db.collection('posts').orderBy('postTime', 'desc').get()
		.then(docs => {
			const posts = []
			docs.forEach(doc => {
				posts.push({ ...doc.data(), id: doc.id })
			})
			return posts
		})
}

Action: getPostsByPage(取得某一頁的文章列表)

列出第 payload.pageNum 頁,
且一頁最多 payload.perPage 筆文章,
且使用 where('isShow', '==', true) 只顯示使用者可以看到的文章。

async getPostsByPage ({}, payload) {
	let postsCol = db.collection('posts').where('isShow', '==', true).orderBy('postTime', 'desc')
	let docs = await postsCol.get()
		.then(({ docs }) => docs)
	let startAt = (payload.pageNum - 1) * payload.perPage
	let page = docs[startAt] ? Number(payload.pageNum) : 1
	let size = docs.length
	let pageLength = Math.ceil(size / payload.perPage)
	if (size === 0) return {
		page: 1,
		size: 1,
		posts: []
	}
	let postTime = docs[startAt]
	? docs[startAt].data().postTime
	: docs[0].data().postTime

	return await postsCol.startAt(postTime).limit(payload.perPage).get()
		.then(({ docs }) => {
			const posts = []
			docs.forEach(doc => {
				posts.push({ ...doc.data(), id: doc.id })
			})
			return {
				page,
				pageLength,
				posts
			}
		})
}

Action: getPostsTag(取得某一個標籤的所有文章)

透過 where('tags', 'array-contains', tagId) 來篩選出擁有該標籤的所有文章。

getPostsTag ({}, tagId) {
	return db.collection('posts').where('isShow', '==', true).where('tags', 'array-contains', tagId).get()
		.then(docs => {
			const posts = []
			docs.forEach(doc => {
				posts.push({ ...doc.data(), id: doc.id })
			})
			return posts
		})
}

Action: getPostByPostId(取得某一篇文章的內容)

根據 postId 取的該文章內容。

getPostByPostId ({}, postId) {
	return db.collection('posts').doc(postId).get()
		.then(doc => doc.data())
}

Action: getPosts(取得所有文章列表)

取得所有使用者可見的文章列表,並按照發布日期排序。

getPosts () {
	return db.collection('posts').where('isShow', '==', true).orderBy('postTime', 'desc').get()
		.then(({ docs }) => {
			const posts = []
			docs.forEach(doc => {
				posts.push({ ...doc.data(), id: doc.id })
			})
			return posts
		})
}

建立索引

注意:記得要回 firebase 的 Database 建立索引如下圖:

023-001

程式碼放在以下 branch:

明天開始利用這些開發好的 actions 切版,
今天就暫時無法 Demo 了。

023-module-tags-post

指令:

git clone -b 023-module-tags-post --single-branch https://github.com/hunterliu1003/blog.git
cd blog
npm install

上一篇
#22 Vuex Module Registration & Firebase 登入功能
下一篇
#24 撰寫所有 admin 相關頁面切版與串接資料
系列文
用 Nuxt.js 2.0, Vuetify, Storybook, Firebase 建一個 Blog30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言