Codelab Web Cloud Firestore

Sasaran

Dalam codelab ini, Anda akan membangun sebuah aplikasi web rekomendasi restoran didukung oleh Cloud Firestore .

img5.png

Apa yang akan Anda pelajari?

  • Membaca dan menulis data ke Cloud Firestore dari aplikasi web
  • Dengarkan perubahan data Cloud Firestore secara real time
  • Gunakan Firebase Authentication dan aturan keamanan untuk mengamankan data Cloud Firestore
  • Tulis kueri Cloud Firestore yang kompleks

Apa yang Anda butuhkan?

Sebelum memulai codelab ini, pastikan Anda telah menginstal:

Buat proyek Firebase

  1. Dalam Firebase konsol , klik proyek Tambah, kemudian nama FriendlyEats proyek Firebase.

Ingat ID Proyek untuk proyek Firebase Anda.

  1. Klik Buat proyek.

Aplikasi yang akan kita bangun menggunakan beberapa layanan Firebase yang tersedia di web:

  • Firebase Otentikasi dengan mudah mengidentifikasi pengguna Anda
  • Cloud Firestore untuk menyimpan data terstruktur pada awan dan mendapatkan notifikasi instan ketika data diperbarui
  • Firebase Hosting untuk tuan rumah dan melayani aset statis Anda

Untuk codelab khusus ini, kami telah mengonfigurasi Firebase Hosting. Namun, untuk Firebase Auth dan Cloud Firestore, kami akan memandu Anda melalui konfigurasi dan pengaktifan layanan menggunakan Firebase console.

Aktifkan Otentikasi Anonim

Meskipun autentikasi bukanlah fokus dari codelab ini, penting untuk memiliki beberapa bentuk autentikasi di aplikasi kita. Kami akan menggunakan Anonymous login - yang berarti bahwa pengguna akan diam-diam masuk tanpa diminta.

Anda harus mengaktifkan Anonymous login.

  1. Dalam Firebase konsol, temukan bagian Build di nav kiri.
  2. Klik Authentication, kemudian klik Sign-in tab metode (atau klik disini untuk langsung ke sana).
  3. Aktifkan Anonymous Sign-in Provider, lalu klik Simpan.

img7.png

Ini akan memungkinkan aplikasi untuk masuk secara diam-diam kepada pengguna Anda saat mereka mengakses aplikasi web. Jangan ragu untuk membaca dokumentasi Anonymous Authentication untuk mempelajari lebih lanjut.

Aktifkan Cloud Firestore

Aplikasi ini menggunakan Cloud Firestore untuk menyimpan dan menerima informasi dan peringkat restoran.

Anda harus mengaktifkan Cloud Firestore. Pada bagian Build Firebase konsol, klik Firestore Database. Klik Membuat database di panel Cloud Firestore.

Akses ke data di Cloud Firestore dikendalikan oleh Aturan Keamanan. Kita akan berbicara lebih banyak tentang aturan nanti di codelab ini, tetapi pertama-tama kita perlu menetapkan beberapa aturan dasar pada data kita untuk memulai. Dalam tab Aturan dari konsol Firebase menambahkan aturan berikut dan kemudian klik Publikasikan.

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      //
      // WARNING: These rules are insecure! We will replace them with
      // more secure rules later in the codelab
      //
      allow read, write: if request.auth != null;
    }
  }
}

Aturan di atas membatasi akses data ke pengguna yang masuk, yang mencegah pengguna yang tidak diautentikasi untuk membaca atau menulis. Ini lebih baik daripada mengizinkan akses publik tetapi masih jauh dari aman, kami akan menyempurnakan aturan ini nanti di codelab.

Mengkloning repositori GitHub dari baris perintah:

git clone https://github.com/firebase/friendlyeats-web

Kode contoh harus telah diklon ke dalam 📁 friendlyeats-web direktori. Mulai sekarang, pastikan untuk menjalankan semua perintah Anda dari direktori ini:

cd friendlyeats-web

Impor aplikasi pemula

Menggunakan IDE Anda (WebStorm, Atom, Sublime, Visual Studio Kode ...) terbuka atau mengimpor 📁 friendlyeats-web direktori. Direktori ini berisi kode awal untuk codelab yang terdiri dari aplikasi rekomendasi restoran yang belum berfungsi. Kami akan membuatnya berfungsi di seluruh codelab ini sehingga Anda perlu segera mengedit kode di direktori itu.

Firebase Command Line Interface (CLI) memungkinkan Anda menyajikan aplikasi web secara lokal dan menerapkan aplikasi web ke Firebase Hosting.

  1. Instal CLI dengan menjalankan perintah npm berikut:
npm -g install firebase-tools
  1. Verifikasi bahwa CLI telah diinstal dengan benar dengan menjalankan perintah berikut:
firebase --version

Pastikan versi Firebase CLI adalah v7.4.0 atau yang lebih baru.

  1. Otorisasi Firebase CLI dengan menjalankan perintah berikut:
firebase login

Kami telah menyiapkan template aplikasi web untuk menarik konfigurasi aplikasi Anda untuk Firebase Hosting dari direktori dan file lokal aplikasi Anda. Namun untuk melakukannya, kami perlu mengaitkan aplikasi Anda dengan proyek Firebase Anda.

  1. Pastikan baris perintah Anda mengakses direktori lokal aplikasi Anda.
  2. Kaitkan aplikasi Anda dengan proyek Firebase Anda dengan menjalankan perintah berikut:
firebase use --add
  1. Bila diminta, pilih ID Proyek Anda, kemudian memberikan proyek Firebase Anda alias.

Alias ​​​​berguna jika Anda memiliki banyak lingkungan (produksi, pementasan, dll). Namun, untuk codelab ini, mari kita menggunakan alias default .

  1. Ikuti instruksi yang tersisa di baris perintah Anda.

Kami siap untuk benar-benar mulai bekerja di aplikasi kami! Ayo jalankan aplikasi kita secara lokal!

  1. Jalankan perintah Firebase CLI berikut:
firebase emulators:start --only hosting
  1. Baris perintah Anda akan menampilkan respons berikut:
hosting: Local server: http://localhost:5000

Kami menggunakan Firebase Hosting emulator untuk melayani aplikasi kita secara lokal. Aplikasi web sekarang harus tersedia dari http: // localhost: 5000 .

  1. Buka aplikasi di http: // localhost: 5000 .

Anda akan melihat salinan FriendlyEats yang telah terhubung ke proyek Firebase Anda.

Aplikasi secara otomatis terhubung ke proyek Firebase Anda dan secara diam-diam membuat Anda masuk sebagai pengguna anonim.

img2.png

Di bagian ini, kami akan menulis beberapa data ke Cloud Firestore sehingga kami dapat mengisi UI aplikasi. Hal ini dapat dilakukan secara manual melalui Firebase konsol , tapi kami akan melakukannya dalam aplikasi itu sendiri untuk menunjukkan Cloud Firestore tulis dasar.

Model data

Data Firestore dibagi menjadi koleksi, dokumen, bidang, dan subkoleksi. Kami akan menyimpan masing-masing restoran sebagai dokumen koleksi tingkat atas disebut restaurants .

img3.png

Kemudian, kami akan menyimpan setiap review di sebuah subcollection disebut ratings di bawah masing-masing restoran.

img4.png

Tambahkan restoran ke Firestore

Objek model utama di aplikasi kami adalah restoran. Mari kita menulis beberapa kode yang menambahkan dokumen restoran ke restaurants koleksi.

  1. Dari file yang didownload, buka scripts/FriendlyEats.Data.js .
  2. Cari fungsi FriendlyEats.prototype.addRestaurant .
  3. Ganti seluruh fungsi dengan kode berikut.

FriendlyEats.Data.js

FriendlyEats.prototype.addRestaurant = function(data) {
  var collection = firebase.firestore().collection('restaurants');
  return collection.add(data);
};

Kode di atas menambahkan dokumen baru ke restaurants koleksi. Data dokumen berasal dari objek JavaScript biasa. Kami melakukan ini dengan terlebih dahulu mendapatkan referensi ke Cloud Firestore koleksi restaurants kemudian add 'ing data.

Mari tambahkan restoran!

  1. Kembali ke aplikasi FriendlyEats Anda di browser Anda dan segarkan.
  2. Klik Add Mock data.

Aplikasi ini secara otomatis akan menghasilkan satu set acak restoran benda, kemudian memanggil Anda addRestaurant fungsi. Namun, Anda tidak akan belum melihat data dalam aplikasi web Anda yang sebenarnya karena kita masih perlu untuk mengimplementasikan mengambil data (bagian berikutnya dari codelab yang).

Jika Anda menavigasi ke tab Cloud Firestore di Firebase konsol, meskipun, Anda harus sekarang melihat dokumen baru di restaurants koleksi!

img6.png

Selamat, Anda baru saja menulis data ke Cloud Firestore dari aplikasi web!

Di bagian berikutnya, Anda akan mempelajari cara mengambil data dari Cloud Firestore dan menampilkannya di aplikasi Anda.

Di bagian ini, Anda akan mempelajari cara mengambil data dari Cloud Firestore dan menampilkannya di aplikasi Anda. Dua langkah utama adalah membuat kueri dan menambahkan pendengar snapshot. Listener ini akan diberi tahu tentang semua data yang ada yang cocok dengan kueri dan akan menerima pembaruan secara real time.

Pertama, mari buat kueri yang akan menyajikan daftar restoran default tanpa filter.

  1. Kembali ke file scripts/FriendlyEats.Data.js .
  2. Cari fungsi FriendlyEats.prototype.getAllRestaurants .
  3. Ganti seluruh fungsi dengan kode berikut.

FriendlyEats.Data.js

FriendlyEats.prototype.getAllRestaurants = function(renderer) {
  var query = firebase.firestore()
      .collection('restaurants')
      .orderBy('avgRating', 'desc')
      .limit(50);

  this.getDocumentsInQuery(query, renderer);
};

Pada kode di atas, kita membangun query yang akan mengambil hingga 50 restoran dari koleksi top-level bernama restaurants , yang diperintahkan oleh rata-rata rating (saat ini semua nol). Setelah kami menyatakan query ini, kami menyebarkannya ke getDocumentsInQuery() metode yang bertanggung jawab untuk loading dan rendering data.

Kami akan melakukan ini dengan menambahkan pendengar snapshot.

  1. Kembali ke file scripts/FriendlyEats.Data.js .
  2. Cari fungsi FriendlyEats.prototype.getDocumentsInQuery .
  3. Ganti seluruh fungsi dengan kode berikut.

FriendlyEats.Data.js

FriendlyEats.prototype.getDocumentsInQuery = function(query, renderer) {
  query.onSnapshot(function(snapshot) {
    if (!snapshot.size) return renderer.empty(); // Display "There are no restaurants".

    snapshot.docChanges().forEach(function(change) {
      if (change.type === 'removed') {
        renderer.remove(change.doc);
      } else {
        renderer.display(change.doc);
      }
    });
  });
};

Pada kode di atas, query.onSnapshot akan memicu callback nya setiap kali ada perubahan ke hasil query.

  • Pertama kali, callback dipicu dengan seluruh hasil set query - yang berarti seluruh restaurants koleksi dari Cloud Firestore. Kemudian melewati semua dokumen individu ke renderer.display fungsi.
  • Ketika dokumen dihapus, change.type sama dengan removed . Jadi dalam hal ini, kami akan memanggil fungsi yang menghapus restoran dari UI.

Sekarang setelah kita mengimplementasikan kedua metode, segarkan aplikasi dan verifikasi bahwa restoran yang kita lihat sebelumnya di konsol Firebase sekarang terlihat di aplikasi. Jika Anda berhasil menyelesaikan bagian ini, maka aplikasi Anda sekarang membaca dan menulis data dengan Cloud Firestore!

Saat daftar restoran Anda berubah, pendengar ini akan terus memperbarui secara otomatis. Coba buka konsol Firebase dan hapus restoran secara manual atau ubah namanya - Anda akan segera melihat perubahannya di situs Anda!

img5.png

Sejauh ini, kami telah menunjukkan bagaimana menggunakan onSnapshot untuk mengambil update secara real time; Namun, itu tidak selalu apa yang kita inginkan. Terkadang lebih masuk akal untuk hanya mengambil data sekali.

Kami ingin menerapkan metode yang dipicu saat pengguna mengklik restoran tertentu di aplikasi Anda.

  1. Kembali ke file Anda scripts/FriendlyEats.Data.js .
  2. Cari fungsi FriendlyEats.prototype.getRestaurant .
  3. Ganti seluruh fungsi dengan kode berikut.

FriendlyEats.Data.js

FriendlyEats.prototype.getRestaurant = function(id) {
  return firebase.firestore().collection('restaurants').doc(id).get();
};

Setelah Anda menerapkan metode ini, Anda akan dapat melihat halaman untuk setiap restoran. Cukup klik restoran dalam daftar dan Anda akan melihat halaman detail restoran:

img1.png

Untuk saat ini, Anda tidak dapat menambahkan peringkat karena kami masih perlu menerapkan penambahan peringkat nanti di codelab.

Saat ini, aplikasi kami menampilkan daftar restoran, tetapi tidak ada cara bagi pengguna untuk memfilter berdasarkan kebutuhan mereka. Di bagian ini, Anda akan menggunakan kueri lanjutan Cloud Firestore untuk mengaktifkan pemfilteran.

Berikut ini adalah contoh query sederhana untuk mengambil semua Dim Sum restoran:

var filteredQuery = query.where('category', '==', 'Dim Sum')

Seperti namanya, yang where() metode akan membuat kita Download permintaan hanya anggota dari koleksi yang bidang memenuhi pembatasan kita set. Dalam hal ini, hanya akan men-download restoran di mana category ini Dim Sum .

Di aplikasi kami, pengguna dapat menghubungkan beberapa filter untuk membuat kueri tertentu, seperti "Pizza di San Francisco" atau "Makanan Laut di Los Angeles yang dipesan berdasarkan Popularitas".

Kami akan membuat metode yang membangun kueri yang akan memfilter restoran kami berdasarkan beberapa kriteria yang dipilih oleh pengguna kami.

  1. Kembali ke file Anda scripts/FriendlyEats.Data.js .
  2. Cari fungsi FriendlyEats.prototype.getFilteredRestaurants .
  3. Ganti seluruh fungsi dengan kode berikut.

FriendlyEats.Data.js

FriendlyEats.prototype.getFilteredRestaurants = function(filters, renderer) {
  var query = firebase.firestore().collection('restaurants');

  if (filters.category !== 'Any') {
    query = query.where('category', '==', filters.category);
  }

  if (filters.city !== 'Any') {
    query = query.where('city', '==', filters.city);
  }

  if (filters.price !== 'Any') {
    query = query.where('price', '==', filters.price.length);
  }

  if (filters.sort === 'Rating') {
    query = query.orderBy('avgRating', 'desc');
  } else if (filters.sort === 'Reviews') {
    query = query.orderBy('numRatings', 'desc');
  }

  this.getDocumentsInQuery(query, renderer);
};

Kode di atas menambahkan beberapa where filter dan satu orderBy klausul untuk membangun sebuah query senyawa berdasarkan masukan pengguna. Permintaan kami sekarang hanya akan mengembalikan restoran yang sesuai dengan kebutuhan pengguna.

Refresh aplikasi FriendlyEats Anda di browser Anda, lalu verifikasi bahwa Anda dapat memfilter berdasarkan harga, kota, dan kategori. Saat menguji, Anda akan melihat kesalahan di Konsol JavaScript browser Anda yang terlihat seperti ini:

The query requires an index. You can create it here: https://console.firebase.google.com/project/.../database/firestore/indexes?create_index=...

Error ini karena Cloud Firestore memerlukan indeks untuk sebagian besar kueri gabungan. Mewajibkan indeks pada kueri membuat Cloud Firestore tetap dalam skala besar.

Membuka tautan dari pesan kesalahan akan secara otomatis membuka UI pembuatan indeks di konsol Firebase dengan parameter yang benar diisi. Di bagian berikutnya, kita akan menulis dan menerapkan indeks yang diperlukan untuk aplikasi ini.

Jika kita tidak ingin menjelajahi setiap jalur di aplikasi kita dan mengikuti setiap tautan pembuatan indeks, kita dapat dengan mudah menerapkan banyak indeks sekaligus menggunakan Firebase CLI.

  1. Dalam direktori lokal aplikasi Anda download, Anda akan menemukan firestore.indexes.json berkas.

File ini menjelaskan semua indeks yang diperlukan untuk semua kemungkinan kombinasi filter.

firestore.indexes.json

{
 "indexes": [
   {
     "collectionGroup": "restaurants",
     "queryScope": "COLLECTION",
     "fields": [
       { "fieldPath": "city", "order": "ASCENDING" },
       { "fieldPath": "avgRating", "order": "DESCENDING" }
     ]
   },

   ...

 ]
}
  1. Terapkan indeks ini dengan perintah berikut:
firebase deploy --only firestore:indexes

Setelah beberapa menit, indeks Anda akan aktif dan pesan kesalahan akan hilang.

Di bagian ini, kami akan menambahkan kemampuan bagi pengguna untuk mengirimkan ulasan ke restoran. Sejauh ini, semua tulisan kami bersifat atomik dan relatif sederhana. Jika salah satu dari mereka salah, kami mungkin hanya akan meminta pengguna untuk mencobanya lagi atau aplikasi kami akan mencoba menulis ulang secara otomatis.

Aplikasi kami akan memiliki banyak pengguna yang ingin menambahkan peringkat untuk sebuah restoran, jadi kami perlu mengoordinasikan banyak pembacaan dan penulisan. Pertama review itu sendiri harus disampaikan, maka rating restoran count dan average rating perlu diperbarui. Jika salah satu dari ini gagal tetapi tidak yang lain, kita akan berada dalam keadaan tidak konsisten di mana data di satu bagian database kita tidak cocok dengan data di bagian lain.

Untungnya, Cloud Firestore menyediakan fungsionalitas transaksi yang memungkinkan kami melakukan banyak pembacaan dan penulisan dalam satu operasi atom, memastikan bahwa data kami tetap konsisten.

  1. Kembali ke file Anda scripts/FriendlyEats.Data.js .
  2. Cari fungsi FriendlyEats.prototype.addRating .
  3. Ganti seluruh fungsi dengan kode berikut.

FriendlyEats.Data.js

FriendlyEats.prototype.addRating = function(restaurantID, rating) {
  var collection = firebase.firestore().collection('restaurants');
  var document = collection.doc(restaurantID);
  var newRatingDocument = document.collection('ratings').doc();

  return firebase.firestore().runTransaction(function(transaction) {
    return transaction.get(document).then(function(doc) {
      var data = doc.data();

      var newAverage =
          (data.numRatings * data.avgRating + rating.rating) /
          (data.numRatings + 1);

      transaction.update(document, {
        numRatings: data.numRatings + 1,
        avgRating: newAverage
      });
      return transaction.set(newRatingDocument, rating);
    });
  });
};

Di blok di atas, kita memicu transaksi untuk memperbarui nilai-nilai numerik dari avgRating dan numRatings dalam dokumen restoran. Pada saat yang sama, kita menambahkan baru rating ke ratings subcollection.

Di awal codelab ini, kami menetapkan aturan keamanan aplikasi kami untuk sepenuhnya membuka database untuk membaca atau menulis apa pun. Dalam aplikasi nyata, kami ingin menetapkan aturan yang lebih halus untuk mencegah akses atau modifikasi data yang tidak diinginkan.

  1. Pada bagian Build Firebase konsol, klik Firestore Database.
  2. Klik tab Aturan di bagian Cloud Firestore (atau klik disini untuk langsung ke sana).
  3. Mengganti default dengan aturan berikut, kemudian klik Publikasikan.

firestore.rules

rules_version = '2';
service cloud.firestore {

  // Determine if the value of the field "key" is the same
  // before and after the request.
  function unchanged(key) {
    return (key in resource.data) 
      && (key in request.resource.data) 
      && (resource.data[key] == request.resource.data[key]);
  }

  match /databases/{database}/documents {
    // Restaurants:
    //   - Authenticated user can read
    //   - Authenticated user can create/update (for demo purposes only)
    //   - Updates are allowed if no fields are added and name is unchanged
    //   - Deletes are not allowed (default)
    match /restaurants/{restaurantId} {
      allow read: if request.auth != null;
      allow create: if request.auth != null;
      allow update: if request.auth != null
                    && (request.resource.data.keys() == resource.data.keys()) 
                    && unchanged("name");
      
      // Ratings:
      //   - Authenticated user can read
      //   - Authenticated user can create if userId matches
      //   - Deletes and updates are not allowed (default)
      match /ratings/{ratingId} {
        allow read: if request.auth != null;
        allow create: if request.auth != null
                      && request.resource.data.userId == request.auth.uid;
      }
    }
  }
}

Aturan ini membatasi akses untuk memastikan bahwa klien hanya membuat perubahan yang aman. Sebagai contoh:

  • Pembaruan pada dokumen restoran hanya dapat mengubah peringkat, bukan nama atau data abadi lainnya.
  • Peringkat hanya dapat dibuat jika ID pengguna cocok dengan pengguna yang masuk, yang mencegah spoofing.

Atau untuk menggunakan Firebase console, Anda dapat menggunakan Firebase CLI untuk menerapkan aturan ke proyek Firebase Anda. The firestore.rules file dalam direktori kerja Anda sudah berisi aturan dari atas. Untuk menerapkan aturan ini dari sistem file lokal Anda (daripada menggunakan konsol Firebase), Anda akan menjalankan perintah berikut:

firebase deploy --only firestore:rules

Dalam codelab ini, Anda mempelajari cara melakukan baca dan tulis dasar dan lanjutan dengan Cloud Firestore, serta cara mengamankan akses data dengan aturan keamanan. Anda dapat menemukan solusi lengkap dalam repositori QuickStarts-js .

Untuk mempelajari Cloud Firestore lebih lanjut, kunjungi referensi berikut: