3

I managed my state with vuexfire. For now and testing I bind to each "table" / node in Firebase. As data starts to grow I need to query so I don't send so much data to the client.

For example. I bind to the order "table" with db.ref('orders') but need to bind to orders for just one office (all orders for all offices is in the same node). Something like db.ref('orders').equalTo(xx) xx => parameter for picked office. Is it possible?

Maybe its not a problem, its only orders with a special status so handled orders will be removed but will increase when new office are added. For example 1000 orders (but will increase when new office are added).

Some code -

In firebaseconfig.js

export const dbOfficeRef = db.ref('office')

In App.vue

export default {
  created() {
    this.$store.dispatch('setOfficeRef', dbOfficeRef)
  }
}

In index.js (store / vuex) and actions

setOfficeRef: firebaseAction(({ bindFirebaseRef }, { ref }) => {
       bindFirebaseRef('office', ref)
})

And I have a office array under state. Above is some kind of extended action from vuexfire. I cant pass in may own param-object instead of ref, I get "undefined" all the times and I cant reach my getters to get the parameter to set. I would like to do something like this in the action, bind to office table for a special office (key) -

bindFirebaseRef('office', ref.orderByChild('officeKey').equalTo(key))

--- MORE CODE --- index.js (store)

import Vue from 'vue'
import Vuex from 'vuex'
import { firebaseMutations } from 'vuexfire'
import { firebaseAction } from 'vuexfire'
import { dbOfficesRef } from '../firebaseConfig'

Vue.use(Vuex)

export const store = new Vuex.Store({
    state: {
        offices: []
    },
    getters: {
        getOffices: state => state.offices
    },
    mutations: {
        ...firebaseMutations
    },
    actions: {
        setOfficesRef: firebaseAction(({ bindFirebaseRef }, { ref }) => {
            bindFirebaseRef('offices', ref)
        }),
        setOfficesRef2: firebaseAction(({ bindFirebaseRef }, { ref }) => {
            bindFirebaseRef('offices', ref.orderByChild('city').equalTo('town1'))
        })
    }
})

App.vue

<template>
  <div id="app">
    <div>

        <p><button type="button" @click="setOffice2('town1')">Uppdatera</button></p>

        <ul>
            <li v-for="office in getOffices">
                {{ office.city }}
            </li>
        </ul> 

    </div>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import { dbOfficesRef } from './firebaseConfig'

export default {
    methods: {
    setOffice(city) {
      this.$store.dispatch('setOfficesRef', dbOfficesRef.orderByChild('city').equalTo(city))
    },
    setOffice2(city) {
      this.$store.dispatch('setOfficesRef2', dbOfficesRef.orderByChild('city').equalTo(city))
    },
  computed: {
    ...mapGetters([
        'getOffices'
    ])
  },
  created() {

    this.$store.dispatch('setOfficesRef', dbOfficesRef)

  }

}
</script>

--- FIREBASE ---

offices
  office1
    city: town1
  office2
    city: town2
user2856066
  • 821
  • 1
  • 11
  • 20

2 Answers2

0

You can query against your ref based on equality of a specific child property of each order by using a combination of orderByChild() and equalTo(). orderByChild() is necessary for targeting a specific child property. equalTo is used for matching against items in the database against a value. If the office property of each order is called office, the query would look like:

dbOfficeRef.orderByChild("office").equalTo('someOfficeName')

In terms of actions, try setting the ref query in/prior to the store.$dispatch rather than actually inside your setOfficeRef action. Depending on whether you'd want to load all offices on load prior to an office being selected, created() would could look like the following to load all offices:

created() {
  this.$store.dispatch('setOfficeRef', dbOfficeRef);
}

Then after perhaps the user has selected an office name/value from something like a <select> dropdown. This can trigger a dispatch to action setOfficeRef passing an updated ref with a query using orderByChild() and equalTo():

setOffice: function(office) {
  this.$store.dispatch('setOfficeRef', dbOfficeRef.orderByChild('office').equalTo(office));
}

When calling bindFirebaseRef() any existing binding will be replaced. You binding action can remain in line with the original:

setOfficeRef: firebaseAction(({ bindFirebaseRef }, { ref }) => {
  bindFirebaseRef('office', ref)
})

Here is an updated example in action showing binding to a ref without any query methods and then binding to a ref with orderByChild() and equalTo.

Hopefully that helps!

Note: When querying by child property, you may see a warning along the lines of needing to add an indexOn. This would be added in your Firebase rules file for the orders node.

Alexander Staroselsky
  • 37,209
  • 15
  • 79
  • 91
  • Thanks it works. But I am trying to do that in the vuex action and cant figure out how to access the getters. With hardcoded values it works fine. Any suggestion? – user2856066 May 03 '18 at 22:45
  • You will probably need to share your actions, but wouldn't it be simply passing the value of the dropdown or office selection value to the get action function you have specified? – Alexander Staroselsky May 03 '18 at 23:29
  • Its not so easy. I am using vuexfire action - setTodosRef = firebaseAction(({ bindFirebaseRef, unbindFirebaseRef }, { ref }) and cant find out how to pass own parameters or access getters from inside the action. – user2856066 May 04 '18 at 14:34
  • What I'm saying is you need to update your question with relevant including your vuexfire actions as well as how and when you retrieve the `office` value. You can always set ref in something like `created()`, then dispatch separate actions with the `office` value on something like office select or from url params. More information is needed to understand your use case and flow. Thanks! – Alexander Staroselsky May 04 '18 at 14:55
  • I've up the answer. Try setting setting the ref with query prior to calling the action which would allow you to pass the value from a dropdown/input/whatever prior to dispatching the action. You can continue using your original `setOfficeRef` action this way. You can even switch between the default ref and a ref with query. The jsfiddle referenced in the answer shows this in action at a basic level. – Alexander Staroselsky May 07 '18 at 14:31
  • I really appreciate your help but I think I going to be crazy - its not working. When I structure my code like your code in one file and with – user2856066 May 08 '18 at 21:20
  • In action `setOfficesRef2` it looks like you are still trying to append the Firebase query methods in addition the query methods that you are adding when you execute `this.$store.dispatch('setOfficesRef2'`. Replace `bindFirebaseRef('offices', ref.orderByChild('city').equalTo('town1'))` in `setOfficesRef2` with just `bindFirebaseRef('offices', ref)` as you are already passing that updated ref in the dispatch. – Alexander Staroselsky May 08 '18 at 21:25
  • Thats what I am doing in App.vue and setOffice with no success. – user2856066 May 08 '18 at 21:35
  • You'd pass the values into the `methods` of the component and subsequently into the query methods rather than the action directly. Are you getting an error or what's is happening? The jsfiddle is demonstrating the setting of the ref from component methods. – Alexander Staroselsky May 08 '18 at 21:40
  • The method parameter was not so important in the example because I hardcoded the value but to be clear in the question, I have edit. I don't get any error code - just that nothing happens. – user2856066 May 08 '18 at 21:51
  • Okay, you need to share your data structure for `office`. It's not clear whether the wrong child property is being targeted. Just to be certain, the action `setOfficesRef2` no longer has `ref.orderByChild()...` right? – Alexander Staroselsky May 08 '18 at 22:04
  • Question updated with Firebase. I have a really simple structure just for testing purpose. But it should not be any problem in Firebase because the action 2 with hardcoded parameters works. – user2856066 May 08 '18 at 22:14
0

I am not sure that I completely understand but I have come up with a solution that works for me. I think I have tested it before but for some reason I abandon that solution. Anyway -

  • Its not possible (for me) to change the "ref".
  • Its not possible (for me) to reach the getters (or state) from inside the extended action.

I pass a payload instead of the ref and no brackets around -

(({ bindFirebaseRef }, payload)

Then I can pass the payload with all data -

var payload = {
    ref: ,
    state: '',
    search: '',
    searchval: 
}

And use it in the action -

bindFirebaseRef(state, ref.orderByChild(search).equalTo(searchval))

Maybe it also matters from where you call the dispatch

user2856066
  • 821
  • 1
  • 11
  • 20