简体   繁体   中英

vue.js and firebase query giving wrong array count

something weird is going on. I am using Vue.js and Firebase. my query is simple. I have 3 documents in the database

let tagRef = db.collection('tags')
        tagRef = tagRef.where('gid', '==', this.$store.getters.gid)
        tagRef.onSnapshot(snapshot => {
            this.tags = []
            snapshot.docChanges().forEach(change => {
                let docs = change.doc
                this.tags.push(docs.data())
                console.log(this.tags.length)
            })
        })

as you can see I am logging the array length to the console. when I refresh the page my console log reads 1 1 2 however when a change is made is reads correctly 1 2 3

I am not sure why it is doing this.

When I change the console.log from this.tags.length to this.tags attached are the screen shots of what I get.

on page refresh

在此处输入图片说明

when a change occurs

在此处输入图片说明

any help is greatly appreciated.

UPDATE:

This is a game. players can tag each other. when a player gets tagged they are disabled temporarily until their tag is complete. the second piece is each player can be tagged no more than 3 times.

In the created() hook I query for the tags and I am using the realtime part of firebase so anytime something changes with the tag database the code is updated.

I have a method as seen below:

countTags(team) {
            return this.tags.filter(function (tag) {
                if(tag.tagged == team.team_id){
                    return team
                }
            })
        },

This method is supposed to return the tags based off of the team id. i the html i have this

:class="{'taglimit' : countTags(team).length >= 3}" 

which will add the "taglimit" class if the count is 3 or greater.

SECOND UPDATE:

When I run this query in the created hook i have issues

let tagRef = db.collection('tags')
    tagRef = tagRef.where('gid', '==', this.$store.getters.gid)
    tagRef.onSnapshot(snapshot => {
        this.tags = []
        snapshot.docChanges().forEach(change => {
            let docs = change.doc
            this.tags.push(docs.data())
        })
    })

but when I run this query I don't

let tagRef = db.collection('tags')
        tagRef = tagRef.where('gid', '==', this.$store.getters.gid)
        tagRef.get().then((snapshot) => {
            snapshot.forEach(doc => {
                let tag = doc.data()
                tag.id = doc.id
                this.tags.push(tag)
            })
        }).catch(err => {
            console.log(err)
        })

The problem is I need to update the code every time the tag database changes.

THIRD UPDATE

I think I found the issue. I moved this.tags = [] outside the query and everything appears to be working fine now. so now the query looks like this.

this.tags = []
let tagRef = db.collection('tags')
    tagRef = tagRef.where('gid', '==', this.$store.getters.gid)
    tagRef.onSnapshot(snapshot => {
        snapshot.docChanges().forEach(change => {
            let docs = change.doc
            this.tags.push(docs.data())
            console.log(this.tags.length)
        })
    })

FOURTH UPDATE:

here is the HTML

<v-dialog v-model="dialog" persistent transition="scale-transition" fullscreen light>
            <v-btn
            slot="activator"
            fixed
            dark
            fab
            bottom
            right
            color="blue-grey darken-2"
            class="pulse-button"
            >
            <v-icon>directions_run</v-icon>
            </v-btn>
            <v-card color="rgba(224, 224, 224, .95)">
                <v-container grid-list-md text-xs-center>
                    <v-layout row wrap class="tagform-container">
                        <v-btn dark fab right absolute small color="grey darken-3"  @click="dialog = false"><v-icon>close</v-icon></v-btn>
                        <v-layout justify-center>
                            <v-card-title class="display-2 font-weight-black">TAG!</v-card-title>
                        </v-layout>
                        <v-card-text class="subheading">Select a team you want to tag. Note, you only have one tag per game. Use it wisely!</v-card-text>
                        <v-flex xs4 class="add-flex" v-for="team in activeTeams" :key="team.id" >
                            <div class="tag-card" 
                                :class="{'disabled' : activeTag(team).length > 0, 'taglimit' : countTags(team).length >= 3}" 
                                height="100%" 
                                color="white" 
                                style="background:#fff;" 
                                @click="activeTag(team).length > 0 || countTags(team).length >= 3 ? '' : selectedTeam(team)"
                                >
                                <v-layout justify-center>
                                    <v-card-title class="title">{{team.team_name}}</v-card-title>
                                </v-layout>
                                <v-responsive>
                                    <img class="avatar" v-bind:src="team.url">
                                </v-responsive>
                                <v-flex>
                                    <v-card-text class="body-2 text-uppercase">Tap to select</v-card-text>
                                </v-flex>
                            </div>
                        </v-flex>
                    </v-layout>
                </v-container>
            </v-card>
        </v-dialog>

There is more but this is the part that counts.

Here is some more of the code

data() {
        return {
            feedback: null,
            teams: [],
            taggedteam: null,
            dialog: false,
            stepper: false,
            emojiinput: '',
            search: '',
            e1: 1,
            tag: null,
            tags: [],
            completedtags: [],
            tagstates: []
        }
    },
computed: {
        activeTeams: function () {
            let thisTeam = this.$store.getters.player.team_id
            return this.teams.filter(function (team) {
                if(team.team_id !== thisTeam)
                    return team
            })
        }
    },

One of the Methods:

countTags(team) {
            return this.tags.filter(function (tag) {
                if(tag.tagged == team.team_id){
                    return team
                }
            })
        },

finally the created hook

created(){
        // get teams
        let teamRef = db.collection('teams')
        teamRef = teamRef.where('gid', '==', this.$store.getters.gid)
        teamRef = teamRef.orderBy('team_id')
        teamRef.onSnapshot(snapshot => {
            snapshot.docChanges().forEach(change => {
                if(change.type == 'added') {
                    let docs = change.doc

                    let leaderRef = db.collection('leaderboard')
                    leaderRef = leaderRef.where('gid', '==', this.$store.getters.gid)
                    leaderRef = leaderRef.where('team', '==', docs.data().team_id)
                    leaderRef = leaderRef.where('missioncomplete', '==', true)
                    leaderRef.onSnapshot(snapshot => {
                        if(snapshot.empty) {
                            // team has not completed the mission so they can still be tagged
                            this.teams.push(docs.data())
                        }
                    })

                }
            })
        })

        // get tags
        this.tags = []
        let tagRef = db.collection('tags')
        tagRef = tagRef.where('gid', '==', this.$store.getters.gid)
        tagRef.onSnapshot(snapshot => {
            snapshot.docChanges().forEach(change => {
                let docs = change.doc
                this.tags.push(docs.data())
            })
        })

        // get tag states
        this.tagstates = []
        let tagStateRef = db.collection('tagstate')
        tagStateRef = tagStateRef.where('gid', '==', this.$store.getters.gid)
        tagStateRef = tagStateRef.where('state', '==', true)
        tagStateRef = tagStateRef.orderBy('tag')
        tagStateRef.onSnapshot(snapshot => {
            snapshot.docChanges().forEach(change => {
                let docs = change.doc
                this.tagstates.push(docs.data())
            })
        })

        if(this.$store.getters.player.team_id) {
            // check to see if this player has already tagged someone
            let tagRef = db.collection('tags')
            tagRef = tagRef.where('tagger', '==', this.$store.getters.player.team_id)
            tagRef = tagRef.where('gid', '==', this.$store.getters.gid)
            tagRef.onSnapshot(snapshot => {
                snapshot.docChanges().forEach(change => {
                    let docs = change.doc
                    this.completedtags.push(docs.data())
                })
            })
        }
    }

It's a bit difficult to dive into your code without knowing the exact relationship between teams/tags and their respective limits.

But I've understood from the discussion that you want to change the class of a DOM element if the result of the query is more that 3 documents.

You'll find a possible approach below, which shows how to manange the class change (and also, if needed how to maintain the tags array in the data object, ie being reactive to database changes).

<template>
  <div :class="{ taglimit: isTagLimit }">Test</div>
</template>

<script>
const fb = require("../firebaseConfig.js");
export default {
  data() {
    return {
      tags: [],
      isTagLimit: false
    };
  },

  created: function() {
    let tagRef = fb.db.collection("tags");
    tagRef = tagRef.where("gid", "==", this.$store.getters.gid);
    tagRef.onSnapshot(querySnapshot => {
      console.log(querySnapshot.size);
      //The next if is sufficient to activate the taglimit class
      if (querySnapshot.size > 3) {
        this.isTagLimit = true;
      } else {
        this.isTagLimit = false;
      }
      //If you want to update the tags property
      var t = [];
      querySnapshot.forEach(doc => {
        t.push(doc.data());
      });
      this.tags = t;
    });
  }
};
</script>

<style>
.taglimit {
  color: deeppink;
}
</style>

Note that instead of replacing the entire tags array, you could listen to "atomic" changes in the Query and update the array with the changes, see https://firebase.google.com/docs/firestore/query-data/listen#view_changes_between_snapshots

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM