質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.37%

vueのv-forを使って良いねの数が多い順に表示し、同じ投稿はまとめて表示させたい(ランキング機能)

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 968

score 56

vue.js 勉強中です

vueのv-forを使って良いねの数が多い順に表示し、同じ投稿はまとめて表示させたい(ランキング機能)
さらにいいねの数もそれぞれ表示させたいと考えています。

state
rankings: []

mutation
ranking(state, tests) {
 state.rankings = tests
},

action
rank({commit}) {
 db.collection('goods').orderBy('post_id').get().then(res => {
  var tests = []
   res.forEach(doc => {
    const rank = doc.data()
    rank.id = doc.id
  db.collection('items').doc(rank.post_id).get().then(res => {
     var test = res.data()
      test.id = res.id
      tests.push(test)
    })
   })
  commit('ranking', tests)
 })
}
<template>
 <div v-for="(post, index) in rankposts" :key="index">
  <h4>{{post.title}}</h4>
  <p>{{post.recommend}}</p>
 </div>
</template>

<script>
export default {
  computed: {
    rankposts() {
      **下に2つ自分で考えたコードが書いてあります
    }
  },
  created() {
    this.$store.dispatch('rank')
  },
}
</script>


rankposts()の中身を以下の2つを参考にしましたが、投稿の値が取得できませんでした。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
https://teratail.com/questions/245425

rankposts() {
      const list = this.$store.state.rankings
      function groupBy(objectArray, property) {
        return objectArray.reduce(function (acc, obj) {
          let key = obj[property]
          if (!acc[key]) {
            acc[key] = []
          }
          acc[key].push(obj)
          return acc
        }, {})
      }

      let resultData = groupBy(list, 'id')
      console.log(resultData)

      return resultData
    }
resultDataの中身
{MxKzTenT5M7yPortf9tL: Array(2), Sx9E1WLZR3QMGPLosilW: Array(1), s6KOsBCbRjOIzzzVrYg4: Array(1)}
rankposts() {
      const list = this.$store.state.rankings
      const didlist = list.map(function(data){ 
        return data.id 
      })
      .reduce(function(acc, val){ 
        acc[val] != null ? acc[val]++ : acc[val] = 1; 
        return acc; 
      }, {});
      return didlist
    }

didlistの中身
{MxKzTenT5M7yPortf9tL: 2, Sx9E1WLZR3QMGPLosilW: 1, s6KOsBCbRjOIzzzVrYg4: 1}

どちらもまとめて返してくれるようにはなっているのですが、この返り値から投稿を取得し、表示させたいのですが自分ではたどり着けませんでした。

もしくはstoreのaction内でこんな書き方の方が良いというのがありましたら教えていただきたいです。

どなたか知恵を貸していただきたいです。

よろしくおねがします。

vue 2.6.1

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

ソラで書いたので、動かなかったようで失礼しましたm(_ _)m

実際に動かしてみたのですが、 reduce の仕様と、実現したいことにギャップが有るようですので、forEach を使ってみました。
result という変数を事前に用意しておくことになりますが、こちらを参考になさっていただければ幸いです。

function groupBy(objectArray) {
  const result = [];

  objectArray.forEach((obj) => {
    const index = result.findIndex((r) => r.id === obj.id);
    if (index < 0) {
      result.push({
        id: obj.id,
        article: obj.article,
        rank: 1
      });
    } else {
      result[index].rank += 1;
    }
  });
  return result;
}

reduce を利用する際に initialValue を設定しない場合、配列の最初の要素がアキュムレーターの初期値として使用されますが、その際に [{ id: 'hoge', article: 'huga' }] ではなく { id: 'hoge', article: 'huga' } となってしまい、オブジェクトに対して push する誤った使い方になっていました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/22 06:31 編集

    ありがとうございます!!!
    予想通りの処理が通りました!!
    本当に丁寧な解説、サンプルコードありがとうございます!!
    自分も実装しているうちに、reduceからforeachに変えてやっていたのですが理解が足りず、正しく書けていなかった事に気づけました。
    本当にありがとうございました!

    キャンセル

0

Firestore を利用しているかと思いましたので、その前提でお答えします。

store の rank で items コレクションのドキュメントが取得できており、その中に投稿内容(仮に article)はすでに取得できており、それが groupBy を利用している rankPosts の結果の Array に入っているように思います。

それが正しいのであれば、 

let key = obj[property]
if (!acc[key]) {
  acc[key] = []
}

とするのではなく、

const key = obj.property
const index = acc.findIndex((a) => a.id === key)
if (index < 0) {
  // 記事が acc にない場合
  acc.push({
    id: key,
    article: obj.article
    rank: 1
  })
} else {
  // すでに記事が acc にある場合
  acc[index].rank += 1
}

のようにすれば、投稿内容も保持でき、いいね件数もカウントできます。
オブジェクトの構造は下記のようになり可用性が出たかと思います。

resultData: [
  {
    id: 'MxKzTenT5M7yPortf9tL',
    article: 'ここに記事が入っているはず...',
    rank: 2
  },
  {
    id: 'Sx9E1WLZR3QMGPLosilW',
    article: 'ここに記事が…',
    rank: 1
  },
  {
    id: 's6KOsBCbRjOIzzzVrYg4',
    article: 'ここに…',
    rank: 1
  }
]


いいね件数や記事の内容がわかっているので、ソートすることも可能です。

間違っていたらすいません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/21 08:09 編集

    丁寧にコメントありがとうございます!firestoreを使用しています!
    上記のコードを参考にしてみましたが、どうもうまくいきません。同じ要素が来た時にrankにプラス1されない、また違う要素が来た時にpushするともともとあった要素を書き換える形になってしまい、配列の中に1つのオブジェクトしか入らない。という状態でした。


    function groupBy(objectArray, property) {
    return objectArray.forEach(element => {
    const h = []
    const key = element[property]
    const index = objectArray.findIndex((a) => a.id === key)
    if (index <= 0) {
    h.push({
    id: key,
    article: element,
    rank: 1
    })
    } else {
    h[index].rank += 1
    }
    console.log(h)
    return h;
    })
    }
    if文の条件分岐がおかしいのか、indexの取り方に問題があるのかだと思うのですが。。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る