Using Firebase in a Vue App with Vuexfire — Querying and Replacing Documents
Tags: javascript, webdev, programming, vue
Published: 2021-01-26 01:23:54

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**


The Vuefire library lets us add Firebase database manipulation capabilities right from our Vue app.

In this article, we’ll look at how to use Vuefire and Vuexfire to add support for Cloud Firestore database manipulation into our Vue app.

### Querying the Database

We can query the database and synchronize it with the Vuex store with Vuexfire.

### Sorting

To sort the data that we get from the Firebase database, we can call `orderBy` to sort the data.

`db.js`

```
import firebase from "firebase/app";
import "firebase/firestore";
export const db = firebase
  .initializeApp({ projectId: "project-id" })
  .firestore();
const { Timestamp, GeoPoint } = firebase.firestore;
export { Timestamp, GeoPoint };
```

`main.js`

```
import Vue from "vue";
import App from "./App.vue";
import { firestorePlugin } from "vuefire";
import { vuexfireMutations, firestoreAction } from "vuexfire";
import Vuex from "vuex";
import { db } from "./db";

Vue.use(Vuex);
Vue.use(firestorePlugin);
Vue.config.productionTip = false;

const store = new Vuex.Store({
  state: {
    books: []
  },
  mutations: {
    ...vuexfireMutations
  },
  actions: {
    bindBooksRef: firestoreAction((context) => {
      return context.bindFirestoreRef(
        "books",
        db.collection("books").orderBy("title", "desc")
      );
    })
  },
  getters: {
    books: (state) => {
      return state.books;
    }
  }
});

new Vue({
  store,
  render: (h) => h(App)
}).$mount("#app");
```

`App.vue`

```
<template>
  <div>{{books}}</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";

export default {
  data() {
    return {};
  },
  methods: {
    ...mapActions(["bindBooksRef"])
  },
  computed: {
    ...mapGetters(["books"])
  },
  mounted() {
    this.bindBooksRef();
  }
};
</script>
```

In the `bindBookRef` action, we called the `bindFirestoreRef` method to bind the `books` state to our `books` database collection.

The `orderBy` method sorts the `title` field value in descending order.

Then `state.books` returns an array of `books` object with `title` sorted in descending order.

Since we called `mapGetters` to map the getters to computed properties, we’ll see this displayed in the template.

### Filtering

We can also filter items with the `where` method.

For example, we can write:

`main.js`

```
import Vue from "vue";
import App from "./App.vue";
import { firestorePlugin } from "vuefire";
import { vuexfireMutations, firestoreAction } from "vuexfire";
import Vuex from "vuex";
import { db } from "./db";

Vue.use(Vuex);
Vue.use(firestorePlugin);
Vue.config.productionTip = false;

const store = new Vuex.Store({
  state: {
    books: []
  },
  mutations: {
    ...vuexfireMutations
  },
  actions: {
    bindBooksRef: firestoreAction((context) => {
      return context.bindFirestoreRef(
        "books",
        db.collection("books").where("wordCount", ">", 200)
      );
    })
  },
  getters: {
    books: (state) => {
      return state.books;
    }
  }
});

new Vue({
  store,
  render: (h) => h(App)
}).$mount("#app");
```

We called `where` to only return the documents with `wordCount` bigger than 200.

Then this is what we’ll see in the states and getters.

### Writing to the Database

We have to use the Firebase SDK to write to our Firebase database.

For example, we can write:

`main.js`

```
import Vue from "vue";
import App from "./App.vue";
import { firestorePlugin } from "vuefire";
import { vuexfireMutations, firestoreAction } from "vuexfire";
import Vuex from "vuex";
import { db } from "./db";

Vue.use(Vuex);
Vue.use(firestorePlugin);
Vue.config.productionTip = false;

const store = new Vuex.Store({
  state: {
    books: [],
    book: {}
  },
  mutations: {
    ...vuexfireMutations
  },
  actions: {
    bindBooksRef: firestoreAction((context) => {
      return context.bindFirestoreRef("books", db.collection("books"));
    }),

    updateBook: firestoreAction(async ({ state }, { bookId, title }) => {
      const bookSnapshot = await db.collection("books").doc(bookId).get();
      const book = bookSnapshot.data();
      const newBook = { ...book, title };
      await db.collection("books").doc(bookId).set(newBook);
      console.log("book updated");
    })
  },
  getters: {
    books: (state) => {
      return state.books;
    }
  }
});

new Vue({
  store,
  render: (h) => h(App)
}).$mount("#app");
```

`App.vue`

```
<template>
  <div>
    <button @click="updateBook">update book</button>
    <div>{{books}}</div>
  </div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";

export default {
  data() {
    return {};
  },
  methods: {
    ...mapActions(["bindBooksRef"]),
    updateBook() {
      this.$store.dispatch("updateBook", {
        bookId: "ei4jIGJjcmS7eSRKUxsw",
        title: "baz"
      });
    }
  },
  computed: {
    ...mapGetters(["books"])
  },
  mounted() {
    this.bindBooksRef();
  }
};
</script>
```

In the Vuex store, we have the `updateBook` action to let us get the book we want to update by its `bookId` .

And we want to update the `title` with it.

To do that, we get the `books` collection with the `collection` method.

`doc` gets the document by ID.

`get` gets the snapshot of the query result.

Then the `data` method returns the actual data.

Once we did that, we update the `title` by creating the `newBook` object.

And once we did that, we call `set` to update the document.

In the `App` component, we called `dispatch` in the `updateBook` method to dispatch the `updateBook` Vuex store action to do the update.

Since sync the store state with the collection with `bindFirestoreRef` , the updated items should show automatically.

### Conclusion

We can update the data by using methods from the Firebase SDK.

Since it’s async, we’ve to put the code in actions.

Also, we can sort and filter items when we do the binding of the collection to the state.