Firebaseで「いいね」機能実装してみた

現時点、いいねを加えるところだけ実装しました。
公式のドキュメントがStarだったのでコードはstarですが、やってることは「いいね」です。
ぜひこの記事を読み始める前に、まずいいねを押してからみていただけると幸いです。

今回公式のドキュメントを解読した項目としては

・フィールドの数値に１を加算（いいねを＋１）すること
・フィールドの配列に要素を追加すること
（［0,1］→[0,1,2]みたいな）

環境
VueCLI

Postには、post_idが１から順に数字を振っています。便利。

前半では、postsコレクション内の指定したpost（実際にフロントでクリックするポスト）に対して、starCountを１増やすと言う処理になっています。

後半は、現在ログインしているユーザーのstarCountドキュメントに、starをつけたポストのID（数字）を配列にして入れます。

なぜ配列にするかというと、ドキュメントの読み込み数が減ると思ったからです。
こういう設計の点でのアドバイスは２４時間マジで受け付けてます。よろしくお願いします。

```store.js
actions: {
    addStarCount({ getters ,commit }, postId){
      if(getters.uid){
        firebase.firestore().collection("posts").where('post_id', '==', postId).get().then(doc => {
          var data = doc.docs[0].id;

          firebase.firestore().collection("posts").doc(data).update({
            starCount: firebase.firestore.FieldValue.increment(1)
          })

        })
        firebase.firestore().collection(`users/${getters.uid}/starCount`).doc("starCount").update({
          star_post_id: firebase.firestore.FieldValue.arrayUnion(postId)
        })
        commit('addStarCount')
      }

    },
}

*postIdには、コンポーネント側でポストのIDを渡します。
```

ドキュメントを指定して、updateをする。

```
starCount: firebase.firestore.FieldValue.increment(1)
```
↑でデータベース上の数値に＋１する。()内の数値が１億だったらアクションが発動するたびに１億加算される

```
star_post_id: firebase.firestore.FieldValue.arrayUnion(postId)
```
↑ユーザーがスターをつけたポストのIDが配列になってどんどん追加されていく。




```post.vue
  data() {
    return {
    userStarCounts: [],
   }
 }

  created() {
      firebase.firestore().collection(`users/${this.$store.getters.uid}/starCount`).doc('starCount').get().then(doc => {
          this.userStarCounts = (doc.data().star_post_id)
        })
```

配列の呼び出しは上記のとおり。

良い名前が思いつかなかった。
userStarCountsに、現在ログイン中のユーザーが「いいね」したポストのIDが全て入っています。


次はいいねを消す処理。

```store.js
    deleteStarCount({ getters, commit }, postId){
      if(getters.uid){
        firebase.firestore().collection("posts").where('post_id', '==', postId).get().then(doc => {
          var data = doc.docs[0].id;

          firebase.firestore().collection("posts").doc(data).update({
            starCount: firebase.firestore.FieldValue.increment(-1)
          })

        })
        firebase.firestore().collection(`users/${getters.uid}/starCount`).doc("starCount").update({
          star_post_id: firebase.firestore.FieldValue.arrayRemove(postId)
        })
        commit('deleteStarCount')
      }
    },//deleteStarCountここまで


```

```
starCount: firebase.firestore.FieldValue.increment(-1)
```

さっきは１だったのは−1にしてスターが減る

```
star_post_id: firebase.firestore.FieldValue.arrayRemove(postId)
```

arrayRemoveで、「数字が全く同じやつを配列から削除」できるようです。

ここで、完成したと思って一旦データベース削除してクリアな状態にしてからいいねを押してみたらエラーを吐いた。

##実は１ヶ所ダメなところあります。
どこでしょうか。

ユーザーのstarCountドキュメントにポストを配列でアップデートして追加していくのですがupdateはあくまで「更新」であって、作成とかは含まれないらしいのです。

そこで出てきたのが.setというやつ。

###じゃあそのまま.updateを.setにすると、追加ではなく新規にポストidが1個しかない配列に置き換わってしまう
のでした。

ということで、正解は

```
  firebase.firestore().collection(`users/${getters.uid}/starCount`).doc("starCount").set({
          star_post_id: firebase.firestore.FieldValue.arrayUnion(postId)
        },{ merge: true})
```

最後にmerge:trueをつけることにより、想定の通り「今の配列に追加」を実装することができます。

便利。


##フロント側の最善が思いつかなかった
ポストをそれぞれ子コンポーネントにすることによって、「いいね」の増減を子コンポーネントで実装してます。

```postChild.vue

<template>
<div v-if="userStarCounts.includes(post.post_id)">
      <v-icon v-show="likedDrawer" color="pink accent-2grey" @click="deleteStar(post.post_id)">mdi-heart</v-icon>
      <v-icon v-show="!likedDrawer" color="grey lighten-2" @click="addStar(post.post_id)">mdi-heart</v-icon>
</div>
<div v-else>
      <v-icon v-show="likedDrawer" color="grey lighten-2" @click="addStar(post.post_id)">mdi-heart</v-icon>
      <v-icon v-show="!likedDrawer" color="pink accent-2grey" @click="deleteStar(post.post_id)">mdi-heart</v-icon>
</div>
</template>

  data() {
    return {
      starCount: 0,
      userStarCounts: [],
      likedDrawer: true,
    }
  },

  created() {
      firebase.firestore().collection(`users/${this.$store.getters.uid}/starCount`).doc('starCount').get().then(doc => {
          this.userStarCounts = (doc.data().star_post_id)
        })
},
  methods: {
    addStar(postId){
      this.addStarCount(postId)
      this.starCount ++
      this.likedDrawer = !this.likedDrawer
    },

    deleteStar(postId){
      if(confirm('削除しますか？')){
        this.deleteStarCount(postId)
        this.starCount --
        this.likedDrawer = !this.likedDrawer
      } else{
        alert("削除は取り消されました");
      }
    },
}

```

これで一応実装できました。

が、もっと良いコードが存在すると思います。

vuexだとstateが全てのポストに適用なので、配列とかフィールドとかをmutationsでコミットしないと実装できないので、今回はコンポーネントでゴリ押しました。

v-ifとv-showのところは伸び代しかないので、ご指導ご鞭撻よろしくお願いします。