Using Cloud Firestore in Vue with vue-firestore

Phil Miller

Cloud Firestore is the spiritual successor to Firebase’s popular Realtime Database. While there are many key differences which you can read about here, the main ones that jump out are: a more structured data model, more robust indexed queries, and atomic batch operations.

We’ll be using the individual @firebase namespaced packages (to keep our bundle size down) as well as vue-firestore for some simple Vue bindings.

Installation

If you want to skip installation and get right to it, here's a codesandbox with everything you need, just add your firebase config.

If starting from scratch, use the vue-cli template of your choice (webpack-simple is a good one).

Then install everything you’ll need to get this ‘fired’ up 🔥🚀

$ npm install @firebase/app @firebase/firestore vue-firestore --save

Note: we're using the namespaced packages to avoid importing the larger firebase library.

Configure Firebase

You will need to get your project credentials from the Firebase Console by going to Add Firebase to your web app.

Once you have the credentials, create firebase.js to initialize firestore, replacing the placeholder data with your own.

firebase.js

import { firebase } from "@firebase/app";
import "@firebase/firestore";

const firebaseApp = firebase.initializeApp({
  apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  authDomain: "your-project.firebaseapp.com",
  databaseURL: "https://your-project.firebaseio.com",
  projectId: "your-project",
  storageBucket: "your-project.appspot.com",
  messagingSenderId: "xxxxxxxxxxxx"
});

export const db = firebaseApp.firestore();

If you haven’t done so, add Cloud Firestore to your project in the Firebase Console by going to Database > Get Started > Try Firestore Beta.

Add to Vue with vue-firestore

In index.js let’s make sure Vue is using vue-firestore

index.js

import Vue from 'vue';
import App from './App';
import VueFirestore from 'vue-firestore';

// turns off the 'You are running Vue in development mode.' msg
Vue.config.productionTip = false;

Vue.use(VueFirestore);

new Vue({
  el: '#app',
  template: '<App/>',
  components: { App },
})

Now for the magic. Replace whatever is in App.vue with the following:

App.vue

<template>
  <div id="app">
    <div>
      <input type="text"
        v-model="newReptile"
        @keyup.enter="addReptile">
      <button  @click="addReptile">
        Add Reptile
      </button>
    </div>
    <ul class="reptileList">
      <li v-for="reptile in reptiles" >
        {{ reptile.name }} -
        <button @click="deleteReptile(reptile)">
          Remove
        </button>
      </li>
    </ul>
  </div>
</template>

<script>
  import { db } from './firebase';

  export default {
    name: 'app',
    data() {
      return {
        reptiles: [],
        newReptile: ''
      }
    },
    firestore() {
      return {
        reptiles: db.collection('reptiles'),
      }
    },
    methods: {
      addReptile: function() {
        this.$firestore.reptiles.add(
          {
            name: this.newReptile,
            timestamp: new Date()
          }
        );
        this.newReptile = '';
      },
      deleteReptile: function(reptile) {
        this.$firestore.reptiles.doc(reptile['.key']).delete();
      }
    }
  }
</script>

<style>
  #app {
    font-family: 'Avenir', Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
  }
  .reptileList {
    list-style: none;
  }
</style>

So what’s happening here? We import a reference to our db from firebase.js and use firestore() from vue-firestore to bind our ‘reptiles’ collection in realtime. We create an addReptile method which makes use of add() so we don’t have to worry about generating document IDs. In this case we’re generating a timestamp so that sorting will be easier in the future.

Lastly, we add a deleteReptile method which takes a reptile object as input. The secret sauce here is the .key property which is required to delete (or update) a document. This is possible because the reptiles collection will be returned in this normalized format:

[
    {
        ".key": "-Jtjl482BaXBCI7brMT8",
        "name": "alligator",
        "timestamp": "February 3, 2018 at 9:05:15 AM UTC-5"
    },
    {
        ".key": "-JtjlAXoQ3VAoNiJcka9",
        "name": "crocodile",
        "timestamp": "February 3, 2018 at 9:08:28 AM UTC-5"
    }
]

If everything is working properly your database and app should look something like this:

firestore app preview

👉 That's it! Your app is now 🔥

  Tweet It

🕵 Search Results

🔎 Searching...