JavaScript + Firestore apmācība 2020. gadam: mācieties ar piemēru

Cloud Firestore ir ļoti ātra un bez servera izveidota NoSQL datu bāze, kas lieliski piemērota jebkura izmēra tīmekļa un mobilo lietotņu darbināšanai. Paņemiet pilnu Firestore apguves rokasgrāmatu, kas izveidota, lai parādītu, kā Firestore izmantot kā dzinēju saviem apbrīnojamajiem projektiem no priekšpuses uz aizmuguri.

Satura rādītājs

Darba sākšana ar Firestore

  • Kas ir Firestore? Kāpēc jums to vajadzētu izmantot?
  • Firestore iestatīšana JavaScript projektā
  • Firestore dokumenti un kolekcijas
  • Mūsu datu bāzes pārvaldīšana, izmantojot Firebase konsoli

Notiek datu iegūšana, izmantojot Firestore

  • Datu iegūšana no kolekcijas ar .get ()
  • Abonēšana kolekcijai ar .onSnapshot ()
  • Atšķirība starp .get () un .onSnapshot ()
  • Kolekcijas abonēšanas atcelšana
  • Atsevišķu dokumentu iegūšana

Datu mainīšana, izmantojot Firestore

  • Dokumenta pievienošana kolekcijai ar .add ()
  • Dokumenta pievienošana kolekcijai ar .set ()
  • Esošo datu atjaunināšana
  • Datu dzēšana

Būtiski modeļi

  • Darbs ar apakškolekcijām
  • Noderīgas metodes Firestore laukiem
  • Vaicāšana ar .where ()
  • Datu pasūtīšana un ierobežošana

Piezīme. Jūs varat lejupielādēt šīs apmācības PDF versiju, lai to varētu lasīt bezsaistē.

Kas ir Firestore? Kāpēc jums to vajadzētu izmantot?

Firestore ir ļoti elastīga, viegli lietojama datu bāze mobilo, tīmekļa un serveru izstrādei. Ja esat iepazinies ar Firebase reāllaika datu bāzi, Firestore ir daudz līdzību, taču ar atšķirīgu (iespējams, deklaratīvāku) API.

Šeit ir dažas no funkcijām, kuras Firestore piedāvā tabulā:

⚡️ Viegli iegūstiet datus reāllaikā

Tāpat kā Firebase reāllaika datu bāzē, arī Firestore piedāvā noderīgas metodes, piemēram, .onSnapshot (), kas padara brīnišķīgu iespēju reāllaikā klausīties datu atjauninājumus. Tas padara Firestore par ideālu izvēli projektiem, kas dod priekšroku visjaunāko datu parādīšanai un izmantošanai (piemēram, tērzēšanas lietojumprogrammām).

? Elastība kā NoSQL datu bāze

Firestore ir ļoti elastīga iespēja aizmugurē, jo tā ir NoSQL datu bāze. NoSQL nozīmē, ka dati netiek glabāti tabulās un kolonnās, kā tas būtu standarta SQL datu bāzē. Tas ir strukturēts kā atslēgas vērtību krājums, it kā tas būtu viens liels JavaScript objekts.

Citiem vārdiem sakot, nav shēmas vai vajadzības aprakstīt, kādus datus mūsu datu bāze glabās. Kamēr mēs nodrošināsim derīgas atslēgas un vērtības, Firestore tos glabās.

↕️ Bez piepūles mērogojams

Viens lielisks ieguvums, izvēloties Firestore savai datu bāzei, ir ļoti spēcīgā infrastruktūra, uz kuras tā balstās, kas ļauj ļoti viegli mērogot lietojumprogrammu. Gan vertikāli, gan horizontāli. Neatkarīgi no tā, vai jums ir simtiem vai miljoniem lietotāju. Google serveri spēs apstrādāt jebkuru slodzi, ko tam uzliekat.

Īsāk sakot, Firestore ir lieliska iespēja gan mazām, gan lielām lietojumprogrammām. Mazām lietojumprogrammām tas ir spēcīgs, jo mēs varam daudz paveikt bez daudz iestatīšanas un ar tiem ļoti ātri izveidot projektus. Firestore ir labi piemērots lieliem projektiem, pateicoties tā mērogojamībai.

Firestore iestatīšana JavaScript projektā

Mēs JavaScript izmantosim Firestore SDK. Šajā krāpniecības lapā mēs aplūkosim, kā izmantot Firestore JavaScript projekta kontekstā. Neskatoties uz to, šeit aplūkojamie jēdzieni ir viegli pārsūtāmi uz jebkuru no pieejamajām Firestore klientu bibliotēkām.

Lai sāktu darbu ar Firestore, dodamies uz Firebase konsoli. To varat apmeklēt, dodoties uz vietni firebase.google.com. Lai pierakstītos, jums ir nepieciešams Google konts.

Kad būsim pierakstījušies, izveidosim jaunu projektu un piešķirsim tam nosaukumu.

Kad mūsu projekts būs izveidots, mēs to atlasīsim. Pēc tam mūsu projekta vadības panelī mēs atlasīsim koda pogu.

Tas mums dos kodu, kas nepieciešams, lai integrētu Firestore ar mūsu JavaScript projektu.

Parasti, ja to iestatāt jebkura veida JavaScript lietojumprogrammā, ieteicams to ievietot īpašā failā ar nosaukumu firebase.js. Ja izmantojat jebkuru JavaScript bibliotēku, kurai ir fails package.json, ieteicams instalēt Firebase atkarību ar npm vai dziju.

// with npm npm i firebase // with yarn yarn add firebase

Firestore var izmantot klientā vai serverī. Ja izmantojat Firestore ar Node, jums būs jāizmanto CommonJS sintakse ar prasību. Pretējā gadījumā, ja klientā izmantojat JavaScript, jūs importēsit firebase, izmantojot ES moduļus.

// with Commonjs syntax (if using Node) const firebase = require("firebase/app"); require("firebase/firestore"); // with ES Modules (if using client-side JS, like React) import firebase from 'firebase/app'; import 'firebase/firestore'; var firebaseConfig = { apiKey: "AIzaSyDpLmM79mUqbMDBexFtOQOkSl0glxCW_ds", authDomain: "lfasdfkjkjlkjl.firebaseapp.com", databaseURL: "//lfasdlkjkjlkjl.firebaseio.com", projectId: "lfasdlkjkjlkjl", storageBucket: "lfasdlkjkjlkjl.appspot.com", messagingSenderId: "616270824980", appId: "1:616270824990:web:40c8b177c6b9729cb5110f", }; // Initialize Firebase firebase.initializeApp(firebaseConfig);

Firestore kolekcijas un dokumenti

Ir divi galvenie termini, kas ir svarīgi, lai saprastu, kā strādāt ar Firestore: dokumenti un kolekcijas .

Documents are individual pieces of data in our database. You can think of documents to be much like simple JavaScript objects. They consist of key-value pairs, which we refer to as fields. The values of these fields can be strings, numbers, Booleans, objects, arrays, and even binary data.

document -> { key: value } 

Sets of these documents of these documents are known as collections. Collections are very much like arrays of objects. Within a collection, each document is linked to a given identifier (id).

collection -> [{ id: doc }, { id: doc }]

Managing our database with the Firestore Console

Before we can actually start working with our database we need to create it.

Within our Firebase console, go to the 'Database' tab and create your Firestore database.

Once you've done that, we will start in test mode and enable all reads and writes to our database. In other words, we will have open access to get and change data in our database. If we were to add Firebase authentication, we could restrict access only to authenticated users.

After that, we'll be taken to our database itself, where we can start creating collections and documents. The root of our database will be a series of collections, so let's make our first collection.

We can select 'Start collection' and give it an id. Every collection is going to have an id or a name. For our project, we're going to keep track of our users' favorite books. We'll give our first collection the id 'books'.

Next, we'll add our first document with our newly-created 'books' collection.

Each document is going to have an id as well, linking it to the collection in which it exists.

In most cases we're going to use an  option to give it an automatically generated ID. So we can hit the button 'auto id' to do so, after which we need to provide a field, give it a type, as well as a value.

For our first book, we'll make a 'title' field of type 'string', with the value 'The Great Gatsby', and hit save.

After that, we should see our first item in our database.

Getting data from a collection with .get()

To get access Firestore use all of the methods it provides, we use firebase.firestore(). This method need to be executed every time we want to interact with our Firestore database.

Es ieteiktu izveidot īpašu mainīgo, lai saglabātu vienu atsauci uz Firestore. Šādi rīkojoties, tiek samazināts koda daudzums, ko rakstāt savā lietotnē.

const db = firebase.firestore(); 
Tomēr šajā krāpšanās lapā es katru reizi pieturēšos pie firestore metodes izmantošanas, lai būtu pēc iespējas skaidrāka.

Lai atsauktos uz kolekciju, mēs izmantojam .collection()metodi un kā argumentu norādām kolekcijas ID. Lai iegūtu atsauci uz mūsu izveidoto grāmatu kolekciju, vienkārši ievadiet virkni “grāmatas”.

const booksRef = firebase.firestore().collection('books');

Lai iegūtu visus dokumenta datus no kolekcijas, mēs varam ķēdē izmantot .get()metodi.

.get()atgriež solījumu, kas nozīmē, ka mēs to varam atrisināt, izmantojot .then()atzvanīšanu, vai arī mēs varam izmantot sintaksi async-await, ja izpildām savu kodu async funkcijas ietvaros.

Once our promises is resolved in one way or another, we get back what's known as a snapshot.

For a collection query that snapshot is going to consist of a number of individual documents. We can access them by saying snapshot.docs.

From each document, we can get the id as a separate property, and the rest of the data using the .data() method.

Here's what our entire query looks like:

const booksRef = firebase .firestore() .collection("books"); booksRef .get() .then((snapshot) => { const data = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })); console.log("All data in 'books' collection", data); // [ { id: 'glMeZvPpTN1Ah31sKcnj', title: 'The Great Gatsby' } ] });

Subscribing to a collection with .onSnapshot()

The .get() method simply returns all the data within our collection.

To leverage some of Firestore's realtime capabilities we can subscribe to a collection, which gives us the current value of the documents in that collection, whenever they are updated.

Instead of using the .get() method, which is for querying a single time, we use the .onSnapshot() method.

firebase .firestore() .collection("books") .onSnapshot((snapshot) => { const data = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })); console.log("All data in 'books' collection", data); });

In the code above, we're using what's known as method chaining instead of creating a separate variable to reference the collection.

What's powerful about using firestore is that we can chain a bunch of methods one after another, making for more declarative, readable code.

Within onSnapshot's callback, we get direct access to the snapshot of our collection, both now and whenever it's updated in the future. Try manually updating our one document and you'll see that .onSnapshot() is listening for any changes in this collection.

Difference between .get() and .onSnapshot()

The difference between the get and the snapshot methods is that get returns a promise, which needs to be resolved, and only then we get the snapshot data.

.onSnapshot, however, utilizes synchronous callback function, which gives us direct access to the snapshot.

This is important to keep in mind when it comes to these different methods--we have to know which of them return a promise and which are synchronous.

Unsubscribing from a collection with unsubscribe()

Note additionally that .onSnapshot() returns a function which we can use to unsubscribe and stop listening on a given collection.

This is important in cases where the user, for example, goes away from a given page where we're displaying a collection's data. Here's an example, using the library React were we are calling unsubscribe within the useEffect hook.

When we do so this is going to make sure that when our component is unmounted (no longer displayed within the context of our app) that we're no longer listening on the collection data that we're using in this component.

function App() { const [books, setBooks] = React.useState([]); React.useEffect(() => { const unsubscribe = firebase .firestore() .collection("books") .onSnapshot((snapshot) => { const data = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })); setBooks(data); }); }, []); return books.map(book => ) }

Getting Individual Documents with .doc()

When it comes to getting a document within a collection., the process is just the same as getting an entire collection: we need to first create a reference to that document, and then use the get method to grab it.

After that, however, we use the .doc() method chained on to the collection method. In order to create a reference, we need to grab this id from the database if it was auto generated. After that, we can chain on .get() and resolve the promise.

const bookRef = firebase .firestore() .collection("books") .doc("glMeZvPpTN1Ah31sKcnj"); bookRef.get().then((doc) => { if (!doc.exists) return; console.log("Document data:", doc.data()); // Document data: { title: 'The Great Gatsby' } });

Notice the conditional if (!doc.exists) return; in the code above.

Once we get the document back, it's essential to check to see whether it exists.

If we don't, there'll be an error in getting our document data. The way to check and see if our document exists is by saying, if doc.exists, which returns a true or false value.

If this expression returns false, we want to return from the function or maybe throw an error. If doc.exists is true, we can get the data from doc.data.

Adding document to a collection with .add()

Next, let's move on to changing data. The easiest way to add a new document to a collection is with the .add() method.

All you need to do is select a collection reference (with .collection()) and chain on .add().

Going back to our definition of documents as being like JavaScript objects, we need to pass an object to the .add() method and specify all the fields we want to be on the document.

Let's say we want to add another book, 'Of Mice and Men':

firebase .firestore() .collection("books") .add({ title: "Of Mice and Men", }) .then((ref) => { console.log("Added doc with ID: ", ref.id); // Added doc with ID: ZzhIgLqELaoE3eSsOazu });

The .add method returns a promise and from this resolved promise, we get back a reference to the created document, which gives us information such as the created id.

The .add() method auto generates an id for us. Note that we can't use this ref directly to get data. We can however pass the ref to the doc method to create another query.

Adding a document to a collection with .set()

Another way to add a document to a collection is with the .set() method.

Where set differs from add lies in the need to specify our own id upon adding the data.

This requires chaining on the .doc() method with the id that you want to use. Also, note how when the promise is resolved from .set(), we don't get a reference to the created document:

firebase .firestore() .collection("books") .doc("another book") .set({ title: "War and Peace", }) .then(() => { console.log("Document created"); });

Additionally, when we use .set() with an existing document, it will, by default, overwrite that document.

If we want to merge, an old document with a new document instead of overwriting it, we need to pass an additional argument to .set() and provide the property merge set to true.

// use .set() to merge data with existing document, not overwrite const bookRef = firebase .firestore() .collection("books") .doc("another book"); bookRef .set({ author: "Lev Nikolaevich Tolstoy" }, { merge: true }) .then(() => { console.log("Document merged"); bookRef .get() .then(doc => { console.log("Merged document: ", doc.data()); // Merged document: { title: 'War and Peace', author: 'Lev Nikolaevich Tolstoy' } }); });

Updating existing data with .update()

When it comes to updating data we use the update method, like .add() and .set() it returns a promise.

Lietošanā ir noderīgi, .update()ka atšķirībā no .set()tā netiks pārrakstīts viss dokuments. Tāpat .set()mums patīk atsaukties uz atsevišķu dokumentu.

Lietojot .update(), ir svarīgi izmantot kļūdu apstrādi, piemēram, .catch()atzvanīšanu, ja dokuments nepastāv.

const bookRef = firebase.firestore().collection("books").doc("another book"); bookRef .update({ year: 1869, }) .then(() => { console.log("Document updated"); // Document updated }) .catch((error) => { console.error("Error updating doc", error); }); 

Datu dzēšana ar .delete ()

Mēs varam izdzēst noteiktu dokumentu kolekciju, atsaucoties uz to pēc id un izpildot .delete()metodi, vienkārši. Tas arī dod solījumu.

Šeit ir pamata piemērs, kā izdzēst grāmatu ar ID "cita grāmata":

firebase .firestore() .collection("books") .doc("another book") .delete() .then(() => console.log("Document deleted")) // Document deleted .catch((error) => console.error("Error deleting document", error));
Ņemiet vērā, ka oficiālajā Firestore dokumentācijā nav ieteicams dzēst visas kolekcijas, tikai atsevišķus dokumentus.

Darbs ar apakškolekcijām

Let's say that we made a misstep in creating our application, and instead of just adding books we also want to connect them to the users that made them. T

The way that we want to restructure the data is by making a collection called 'users' in the root of our database, and have 'books' be a subcollection of 'users'. This will allow users to have their own collections of books. How do we set that up?

References to the subcollection 'books' should look something like this:

const userBooksRef = firebase .firestore() .collection('users') .doc('user-id') .collection('books');

Note additionally that we can write this all within a single .collection() call using forward slashes.

The above code is equivalent to the follow, where the collection reference must have an odd number of segments. If not, Firestore will throw an error.

const userBooksRef = firebase .firestore() .collection('users/user-id/books');

To create the subcollection itself, with one document (another Steinbeck novel, 'East of Eden') run the following.

firebase.firestore().collection("users/user-1/books").add({ title: "East of Eden", });

Then, getting that newly created subcollection would look like the following based off of the user's ID.

firebase .firestore() .collection("users/user-1/books") .get() .then((snapshot) => { const data = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })); console.log(data); // [ { id: 'UO07aqpw13xvlMAfAvTF', title: 'East of Eden' } ] });

Useful methods for Firestore fields

There are some useful tools that we can grab from Firestore that enables us to work with our field values a little bit easier.

For example, we can generate a timestamp for whenever a given document is created or updated with the following helper from the FieldValue property.

We can of course create our own date values using JavaScript, but using a server timestamp lets us know exactly when data is changed or created from Firestore itself.

firebase .firestore() .collection("users") .doc("user-2") .set({ created: firebase.firestore.FieldValue.serverTimestamp(), }) .then(() => { console.log("Added user"); // Added user });

Additionally, say we have a field on a document which keeps track of a certain number, say the number of books a user has created. Whenever a user creates a new book we want to increment that by one.

An easy way to do this, instead of having to first make a .get() request, is to use another field value helper called .increment():

const userRef = firebase.firestore().collection("users").doc("user-2"); userRef .set({ count: firebase.firestore.FieldValue.increment(1), }) .then(() => { console.log("Updated user"); userRef.get().then((doc) => { console.log("Updated user data: ", doc.data()); }); }); 

Querying with .where()

What if we want to get data from our collections based on certain conditions? For example, say we want to get all of the users that have submitted one or more books?

We can write such a query with the help of the .where() method. First we reference a collection and then chain on .where().

The where method takes three arguments--first, the field that we're searching on an operation, an operator, and then the value on which we want to filter our collection.

Mēs varam izmantot jebkuru no šiem operatoriem, un lauki, kurus mēs izmantojam, var būt primitīvas vērtības, kā arī masīvi.

<, <=, ==, >, >=, array-contains, in, Vaiarray-contains-any

Lai ielādētu visus lietotājus, kuri ir iesnieguši vairākas grāmatas, mēs varam izmantot šādu vaicājumu.

Pēc tam, kad .where()mums jāpievieno ķēdei .get(). Pēc solījuma atrisināšanas mēs atgūsim to, kas pazīstams kā querySnapshot .

Tāpat kā iegūstot kolekciju, mēs varam atkārtot vaicājumu Snapshot ar, .map()lai iegūtu katra dokumenta ID un datus (laukus):

firebase .firestore() .collection("users") .where("count", ">=", 1) .get() .then((querySnapshot) => { const data = querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })); console.log("Users with > 1 book: ", data); // Users with > 1 book: [ { id: 'user-1', count: 1 } ] });
Ņemiet vērā, ka .where()salikto vaicājumu izveidošanai varat izmantot vairākas metodes.

Vaicājumu ierobežošana un pasūtīšana

Another method for effectively querying our collections is to limit them. Let's say we want to limit a given query to a certain amount of documents.

If we only want to return a few items from our query, we just need to add on the .limit() method, after a given reference.

If we wanted to do that through our query for fetching users that have submitted at least one book, it would look like the following.

const usersRef = firebase .firestore() .collection("users") .where("count", ">=", 1); usersRef.limit(3)

Another powerful feature is to order our queried data according to document fields using .orderBy().

If we want to order our created users by when they were first made, we can use the orderBy method with the 'created' field as the first argument. For the second argument, we specify whether it should be in ascending or descending order.

Lai visus lietotājus sakārtotu pēc to izveides no jaunākajiem līdz vecākajiem, mēs varam izpildīt šādu vaicājumu:

const usersRef = firebase .firestore() .collection("users") .where("count", ">=", 1); usersRef.orderBy("created", "desc").limit(3);

Mēs varam ķēdīt .orderBy()ar .limit(). Lai tas darbotos pareizi, .limit()ir jāsauc pēdējais, nevis iepriekšējais .orderBy().

Vēlaties savu kopiju? ?

Ja vēlaties, lai šī rokasgrāmata būtu pieejama vēlāk, šeit lejupielādējiet visas šīs apmācības krāpniecības lapu.

Noklikšķiniet, lai greifers krāpšanās lapu