firebase_Firebase:5种常见的误解

firebase

by Cathryn Griffiths

凯瑟琳·格里菲思(Cathryn Griffiths)

Firebase:5种常见的误解 (Firebase: 5 way-too-common misconceptions)

I’ve been reading a lot of online commentary recently about Firebase. Mostly — it must be pointed out — written by developers who hate Firebase.

我最近在阅读有关Firebase的许多在线评论。 必须指出的是,大多数情况是由讨厌Firebase的开发人员编写的。

“Complex queries are impossible!” says one.

“不可能进行复杂的查询!” 一说。

“Dumb data modeling!” says another.

“哑数据建模!” 另一个说。

Everything has to be client-side!” complains another.

一切都必须在客户端! ”另一个抱怨。

You can almost hear the little veins standing out on their foreheads.

您几乎可以听到额头上突出的小静脉。

I get it though. The issues they’ve run into are frustrating. But a big part of the problem is a lack of understanding about Firebase, what it can (and can’t!) do.

我明白了。 他们遇到的问题令人沮丧。 但是问题的很大一部分是缺乏对Firebase的理解,它不能(不能!)做什么。

I’ve been working with Firebase over the last few months. At FFunction, we are using Firebase to build a project planning tool called Min. There are some serious misconceptions/myths/misunderstandings about this backend-as-a-service(BaaS) solution. So, I wanted to unpack some of them here.

在过去的几个月中,我一直在与Firebase合作。 在FFunction中 ,我们使用Firebase构建名为Min项目计划工具 。 关于此后端即服务(BaaS)解决方案存在一些严重的误解/误解/误解。 所以,我想在这里拆开其中的一些包装。

By the way: We’re not in any way affiliated with Firebase. I want to add a little nuance to what is becoming a fairly one-sided discussion.

顺便说一句:我们与Firebase没有任何关系。 我想在正成为一个单方面讨论的内容上添加一些细微差别。

误解1:Firebase仅限客户端 (Misconception 1: Firebase is client-side only)

Until recently, Firebase was an exclusively client-side technology. Although, it provided storage and querying capabilities. But the majority of your application logic had to exist and execute on the client. For many developers, this was a total deal breaker. After all, how many web applications these days need no backend?

直到最近,Firebase还是唯一的客户端技术。 虽然,它提供了存储和查询功能。 但是大多数应用程序逻辑必须存在并在客户端上执行。 对于许多开发人员来说,这是一个总的突破。 毕竟,如今有多少Web应用程序不需要后端?

Firebase team actually listened to the requests of the developer community. In March 2017, they introduced Cloud Functions for Firebase. With cloud functions, you can save snippets of code on Google Cloud. This code will run in response to specific Firebase events and HTTP requests. For example, if you want to perform data processing when saving data to the database, you can do that. Also, if you don’t want your application’s API keys exposed in your client-side code, you can do that too.

Firebase团队实际上听了开发人员社区的要求。 在2017年3月,他们推出了Cloud Functions for Firebase 。 借助云功能,您可以将代码段保存在Google Cloud上。 该代码将响应特定的Firebase事件和HTTP请求而运行。 例如,如果要在将数据保存到数据库时执行数据处理,则可以这样做 。 另外,如果您不希望在客户端代码中公开应用程序的API密钥, 也可以这样做

If you’re interested in learning more, I would recommend checking out the Cloud Function for Firebase docs (which have some great examples) and these recently-released tutorials.

如果您有兴趣了解更多信息,我建议您查看Cloud Function for Firebase文档 (其中有一些很棒的示例)以及这些最近发布的教程

误解2:Firebase导致意大利面条式代码 (Misconception 2: Firebase results in spaghetti code)

This makes me think of that old adage: “A poor workman blames their tools!” But let’s dig into this in a little detail.

这让我想到了那句老话:“一个可怜的工人责怪他们的工具!” 但是,让我们稍微深入地研究一下。

Based on my experience thus far, Firebase doesn’t result in spaghetti code. Since Firebase is mostly client side, most of your backend logic will end up on the client. If you’re not careful, you may end up with a pile of messy, unmaintainable code.

根据到目前为止的经验,Firebase不会生成意大利面条式代码 由于Firebase主要是客户端,因此大多数后端逻辑将最终出现在客户端上。 如果您不小心,可能会遇到一堆混乱的,无法维护的代码。

In the early stages of developing Min, we spent a lot of time planning the app. We planned how to model our data, our database structure and the best way to interact with our data. We created a connector for communicating with Firebase. It had all the code for doing CRUD operations and for interacting with Firebase. We built a collection of classes to process the object’s data according to the Firebase database structure.

在开发Min的早期阶段,我们花费了大量时间来规划该应用程序。 我们计划了如何建模数据,数据库结构以及与数据交互的最佳方法。 我们创建了一个用于与Firebase通信的连接器。 它具有用于执行CRUD操作以及与Firebase交互的所有代码。 我们建立了一个类集合,根据Firebase数据库结构处理对象的数据。

This abstraction helped us keep Firebase related logic and application logic separate. Our code was maintainable and easy to debug.

这种抽象帮助我们将与Firebase相关的逻辑和应用程序逻辑分开。 我们的代码可维护且易于调试。

误解三:哑数据建模/重复过多 (Misconception 3: Dumb data modelling / too much duplication)

As the Firebase team describes it, the Firebase database is just one giant JSON tree. Data gets stored as collections of key-value pairs and can have any breadth and depth that you want. There’s a lot of flexibility how you can store your data, which can get you into a lot of trouble if you’re not careful. Let me show this with an example.

正如Firebase团队描述的那样,Firebase数据库只是一棵巨型JSON树 。 数据存储为键-值对的集合,并且可以具有所需的任何广度和深度。 存储数据的方式非常灵活,如果您不小心的话,可能会惹上很多麻烦。 让我用一个例子来说明。

Let say you’re building a basic project management application. You have users and tasks. Users can be assigned to tasks. You might want to store all task information in one database location under the tasks node:

假设您正在构建一个基本的项目管理应用程序。 您有用户和任务。 可以将用户分配给任务。 您可能希望将所有任务信息存储在任务节点下的一个数据库位置:

tasks : {    "001" : {        name         : "Development Round 1"        description  : "Lorem ipsum dolor sit amet elit..."        startDate    : "20170101"        endDate      : "20170201"        loggedHours  : {            "20170101" : "1.66"            "20170102" : "7"            "20170103" : "5.5"        }        assignedStaff : "Cathryn"    }    "002" : {        name : "Development Round 2"        description : "Mauris quis turpis ut ante..."        startDate   : "20170206"        endDate     : "20170228"        loggedHours  : {            "20170206" : "3"            "20170207" : "1"            "20170208" : "4.75"        }        assignedStaff : "Sam"    }    "003" : {        name : "Browser Testing"        description : "Vivamus nec ligula et nulla blandit..."        startDate   : "20170301"        endDate     : "20170303"        loggedHours  : {            "20170301" : "1"            "20170301" : "3"        }        assignedStaff : "Cathryn"    }}

Now let’s say, you want to display task name of all the tasks assigned to Cathryn. To do this, you could query the database to return all tasks whose “assignedStaff” value is “Cathryn”.

现在假设您要显示分配给Cathryn的所有任务的任务名称。 为此,您可以查询数据库以返回其“ assignedStaff”值为“ Cathryn”的所有任务。

firebase.database().ref(“tasks/”).orderByValue(“assignedStaff”).equalTo(“Cathryn”).once(“value”);

The problem with this query is that it’ll return all the task information for a given task that’s assigned to Cathryn, not just the task name. That’s a lot of unnecessary data to download.

该查询的问题在于它将返回分配给Cathryn的给定任务的所有任务信息,而不仅仅是任务名称。 有很多不必要的数据可供下载。

To fix this, Firebase recommends you to denormalize your data(there’s a great how-to about this here). Denormalization is a process of storing redundant copies of data throughout the database, to improve read performance. In our example, we could denormalize our data by adding the following to our database:

要解决此问题,Firebase建议您对数据进行非规范化 ( 此处提供了一个很好的方法 )。 非规范化是在整个数据库中存储数据的冗余副本以提高读取性能的过程。 在我们的示例中,我们可以通过将以下内容添加到数据库中来对数据进行规范化:

tasksByUser : {    "Cathryn" : {        "001" : "Development Round 1"        "003" : "Browser Testing"    }    "Sam" : {        "002" : "Development Round 2"    }}

Now if we want to retrieve the task names for all tasks assigned to Cathryn, we simply need to read from one database location:

现在,如果要检索分配给Cathryn的所有任务的任务名称,我们只需要从一个数据库位置读取:

firebase.database().ref(“/tasksByUser/Cathryn”).once(“value”);

Compared to our previous query, this will return the name of tasks assigned to Cathryn. This results in faster read operations with better performance in the long term.

与我们之前的查询相比,这将返回分配给Cathryn的任务的名称。 从长远来看,这将导致更快的读取操作和更好的性能。

Denormalization may seem like a hack to some. But it’s an imperative strategy when designing a Firebase database for a complex and scalable web application. It requires that you have a deep understanding of the data you want to store and how you’re going to use it.

对某些人来说,非规范化似乎是一个hack。 但是,在为复杂且可扩展的Web应用程序设计Firebase数据库时,这是一项必要的策略。 它要求您对要存储的数据以及如何使用它们有深刻的了解。

Before jumping into building your Firebase database. Take the time to learn about denormalization, how to structure your data, and how to maintain consistency of denormalized data. As the Firebase team has said, “Consider that disk space is cheap, but a user’s time is not.

在开始构建Firebase数据库之前。 花时间学习非规范化如何构造数据以及如何保持非规范化数据的一致性 。 正如Firebase团队所说:“ 考虑磁盘空间便宜,但用户的时间却不大。

If your read times are slow, then chances are that your users won’t be sticking around.

如果您的阅读时间很慢,那么您的用户很可能不会留下来。

Furthermore, inefficient queries that return unnecessary data can be monetarily expensive. Depending on your Firebase pricing plan, you may need to pay as much as $1 per GB downloaded.

此外,返回不必要数据的效率低下的查询可能在经济上昂贵。 根据您的Firebase定价计划,您可能需要为所下载的每GB支付1美元的费用

误解4:Firebase可能导致数据不一致 (Misconception 4: Firebase can lead to data inconsistencies)

If you’re designing your Firebase database in a correct way. Chances are your data is denormalized across multiple database locations. And if your data is stored in multiple locations, then you’re probably wondering… “how am I going to keep all that data consistent?”

如果您以正确的方式设计Firebase数据库。 您的数据很可能在多个数据库位置之间被非规范化。 如果您的数据存储在多个位置,那么您可能想知道……“我将如何使所有数据保持一致?”

In a normal case, when sending data to Firebase, you specify one database path and the data you want to store there. Let’s return to the example, to update a task name (before using denormalization), I would do this:

在正常情况下,将数据发送到Firebase时,您可以指定一个数据库路径以及要在其中存储的数据。 让我们回到该示例,以更新任务名称(在使用非规范化之前),我将这样做:

firebase.database().ref(“tasks/001/name”).set(“Here’s the new name”);

Now with denormalization, I may update a task’s name by doing two write operations:

现在使用非规范化,我可以通过执行两个写操作来更新任务的名称:

firebase.database().ref(“tasks/001/name”).set(“Here’s the new name”);
firebase.database().ref(“tasksByUser/Cathryn/001”).set(“Here’s the new name”);

But doing those two write operations can lead to data inconsistencies. What if one of the write operations fails, and the other one doesn’t? What I need is an atomic write operation, allowing me to write to database paths at the same time. For this, Firebase provides multipath updates to address this exact problem. You can watch a great how-to on this here. Now, to update a task name, we just need to do the following:

但是执行这两个写操作可能会导致数据不一致。 如果写入操作之一失败,而另一个未失败怎么办? 我需要的是原子写入操作,使我可以同时写入数据库路径。 为此,Firebase提供了多路径更新来解决此确切问题。 您可以在这里观看一个很棒的方法。 现在,要更新任务名称,我们只需执行以下操作:

firebase.database().ref().update({    “tasks/001/name” : “Here’s the new name”,    “tasksByUser/Cathryn/001” : “Here’s the new name”});

If the update fails at any of the database paths, the whole update will fail. As long as you use multipath updates, your data should always be consistent.

如果更新在任何数据库路径上失败,则整个更新将失败。 只要您使用多路径更新,您的数据就应该始终保持一致。

误解5:查询功能非常有限 (Misconception 5: Very limited querying capabilities)

Firebase has limited querying capabilities. You can sort data by keys or value and filter data by equality or using ranges.

Firebase的查询功能有限。 您可以按键或值对数据进行排序,并按等式或使用范围对数据进行过滤。

For example, using the examples of tasks and users. I could make a query to retrieve tasks that start on, before, or after 20170601. I could also make a query to retrieve all task assigned to Cathryn, or who have hours logged for 20170203. But what I can’t do is filter by multiple values or keys. For example, I can’t make a query to retrieve the tasks that assigned to Cathryn and start after 20170601. A query to retrieve the tasks that have hours logged on 20170203 and 20170304 will also won’t work.

例如,使用任务和用户的示例。 我可以进行查询以检索开始于20170601之前或之后的任务。我还可以进行查询以检索分配给Cathryn的所有任务,或者记录了20170203小时的任务。但是我无法做的是通过筛选多个值或键。 例如,我无法进行查询以检索分配给Cathryn 在20170601之后开始的任务。检索具有在20170203和20170304上已记录小时数的任务的查询也将不起作用。

Querying or filtering on multiple keys or values doesn’t work, and developers love to complain about it. But if they did their research, they’d realize there’s actually a pretty good reason for it. Since Firebase is a real-time database and designed for speed, Firebase only supports operations that it can guarantee to be fast. If you want to do some complex queries, you’ll have to design your database accordingly. Complex queries aren’t impossible, you have to plan ahead for them.

查询或过滤多个键或值不起作用,开发人员喜欢抱怨它。 但是,如果他们进行了研究,他们会意识到实际上有充分的理由。 由于Firebase是实时数据库,并且为提高速度而设计,因此Firebase仅支持可以保证快速的操作 。 如果要进行一些复杂的查询,则必须相应地设计数据库。 复杂的查询并非不可能,您必须为它们预先计划。

For example, if I wanted to make a query to retrieve all tasks assigned to Cathryn that start on 20170201. I could add a “staff_startDate” property to my tasks, as follows:

例如,如果我要查询以检索自20170201开始分配给Cathryn的所有任务。我可以在任务中添加“ staff_startDate”属性,如下所示:

tasks : {    "001" : {        ...        startDate       : "20170101"        assignedStaff   : "Cathryn"        staff_startDate : “Cathryn_20170101”        ...    }    ...}

Then, I would just need to query it this way:

然后,我只需要以这种方式查询它:

firebase.database().ref(“/tasks/”).orderByChild(“staff_startDate”).equalTo(“Cathryn_20170101”);

I highly recommend you watch Common SQL Queries converted for the Firebase Database and Firebase Database Querying 101. Knowing how to structure and query your data will allow you to do more advanced queries. It will save you a lot of headaches down the road.

我强烈建议您观看针对Firebase数据库Firebase数据库查询101 转换的通用SQL查询 。 了解如何构造和查询数据将使您能够进行更多高级查询。 它将为您免去很多麻烦。

I decided to follow this article with a Firebase Best Practices checklist. If you put your email in the box below, I’ll send it to you.

我决定在本文后面附有Firebase最佳做法清单。 如果您将电子邮件放在下面的框中,我会发送给您。

In the meantime, I’d like to hear from other developers using Firebase.

同时,我想听听其他使用Firebase的开发人员的信息。

Is anyone else liking Firebase?

还有其他人喜欢Firebase吗?

Not so much?

没那么多?

Banging your head against the screen?

把头撞在屏幕上?

Talk to me, developers. Comments are open.

与我交谈,开发人员。 评论是开放的。

翻译自: https://www.freecodecamp.org/news/firebase-5-way-too-common-misconceptions-93b843ee1b93/

firebase

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值