如何将Firebase Firestore用作数据库

将Firestore设置为数据库的教程,这是解决存储问题的非常方便的解决方案!

我需要为我的一些数据创建存储会员俱乐部,我教编程的地方。

我希望我的用户能够通过单击按钮手动说“我完成了本课程”。

基本上,我想为每个用户存储一个特定的对象。

设置Firebase

我决定用火力基地为此,尤其是Firestore数据库他们提供。

它的免费层很宽敞,每月最多可存储1GB数据和10GB网络传输。远远超出了我对我所需要的估计!

在以下位置打开Firebase网站https://firebase.google.com/

Firebase是Google的产品,因此,一旦您登录到Google,您实际上也将登录到Firebase。

我通过单击“创建项目”创建了一个新的Firebase项目。

我给它起了个名字:

就是这样:

我单击了iOS和Android旁边的“ Web”图标,然后输入了应用名称:

Firebase立即给了我所需的访问密钥,以及一些示例代码:

之后,Firebase提示我为数据库添加一些安全规则。

默认情况下,您可以选择两件事:向所有人开放或对所有人封闭。我开始向所有人开放,他们称之为测试模式

而已!我已经准备好了,创建了一个收藏夹。

什么是收藏品?用Firestore术语,我们可以创建许多不同的集合,并为每个集合分配文档。

然后,文档可以包含字段和其他集合。

它与其他NoSQL数据库没有太大区别,例如MongoDB的

我强烈建议观看有关该主题的YouTube播放列表,做得很好。

所以我添加了我的收藏集users

我想使用一个特殊的字符串来标识每个用户,我称之为id

前端代码

我们现在进入JavaScript部分。

在页脚中,我包括了Firebase提供的这两个文件:

<script src="https://www.gstatic.com/
firebasejs/7.2.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/
firebasejs/7.2.1/firebase-firestore.js"></script>

然后我加了一个DOMContentLoaded事件侦听器,以确保在DOM准备就绪时运行了代码:

<script>
document.addEventListener('DOMContentLoaded', event => {

}) </script>

在其中,我添加了Firebase配置:

const firebaseConfig = {
  apiKey: "MY-API-KEY",
  authDomain: "MY-AUTH-DOMAIN",
  projectId: "MY-PROJECT-ID"
}

我将此对象传递给firebase.initializeApp(),然后我打电话firebase.firestore()获取对数据库对象的引用:

firebase.initializeApp(firebaseConfig)
const db = firebase.firestore()

现在,我创建了一个脚本,使用一个简单的循环从后端拥有的列表中填充用户标识:

const list = [/*...my list...*/]

list.forEach(item => { db.collection(‘users’).doc(item).set({}) })

..然后我运行了一次,以填充数据库。我基本上以编程方式为每个用户创建一个文档

这非常重要,因为一旦创建了文档,就意味着我可以限制仅更新那些文档的权限,而不允许添加新文档或删除它们(稍后我们将做)

好的,现在我有了一些复杂的逻辑来识别用户ID和课程ID,我将不再赘述,因为它与此处的任务无关。

一旦收集到该信息,就可以得到对该对象的引用:

const id = /* the user ID */
const course = /* the course ID */
const docRef = db.doc(`membership/${id}`)

伟大的!现在我可以从Firebase获取文档参考:

docRef.get().then(function(doc) {
  if (doc.exists) {
    const data = doc.data()
    document.querySelector('button')
      .addEventListener('click', () => {
      data[course] = true
      docRef.update(data)
    })
  } else {
    //user does not exist..
  }
})

我的逻辑实际上要复杂得多,因为我还有其他活动部分,但是您明白了!

我通过调用来初始化文档数据doc.data()然后,当我单击按钮(我假设它是说“我完成了课程”的按钮)时,我们将true俱乐部标识的布尔值。

稍后,在随后加载课程列表页面时,如果课程完成,我可以初始化页面并分配课程,如下所示:

for (const [key, value] of Object.entries(data[course])) {
  const element = document.querySelector('.course-' + course)
  if (element) {
    element.classList.add('completed')
  }
}

权限问题

我是在测试模式下启动Firebase的,还记得吗?这使得数据库对所有人开放-每个人都具有访问密钥,这些访问密钥是公开的,并在发布到前端的代码中发布。

因此,我必须做一件事:确定允许的权限级别。

我偶然发现了一个非常重要的问题。

使用Firebase控制台,在规则,我们可以调整权限。最初,这是默认规则:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}

我将规则更改为read, update,因此只能更新文档,而不能创建新文档:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, update;
    }
  }
}

但是我无法阻止人们使用Firebase API(现在可以在浏览器中免费使用)来浏览并列出集合中的所有其他文档,从而可以访问其他人的文件。

尽管这不能处理任何敏感数据,但无法交付此代码。

通过自定义API将代码从前端移动到后端

许可问题是路障。

我考虑过删除所有的代码,但最终我发现可以完全隐藏浏览器中的所有API访问,并使用Node.js服务运行Firebase API。

这也是隐藏服务所需私钥/私钥的一种常用方法:将它们隐藏在您控制的服务器后面。

我没有从浏览器调用Firebase,而是在自己的服务器上创建了一组端点,例如:

  • 发布到/course将课程设置为已完成
  • 发布到/data获取与用户关联的数据

我使用提取API

const options = {
    method: 'POST',
    headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
    },
    body: JSON.stringify({ id, course, lesson })
}
const url = BASE_URL + '/lesson'
fetch(url, options).catch(err => {
    console.error('Request failed', err)
})

所有带有单击按钮等等的逻辑都保留在客户端代码中,当然,我只是将Firebase逻辑移开了。

在Node.js服务器端,我安装了官方firebase包使用npm install firebase并要求它:

const firebase = require('firebase')

我建立了一个表示要使用的服务器CORS我初始化了Firebase:

const firebaseConfig = {
  apiKey: process.env.APIKEY,
  authDomain: process.env.AUTHDOMAIN,
  projectId: process.env.PROJECTID
}

firebase.initializeApp(firebaseConfig) const db = firebase.firestore()

然后该代码与我在前端中使用的代码完全相同,除了它现在可以在HTTP端点调用上触发。这是从我们的收藏集中返回特定文档的代码

const getData = async (id) =>  {
  const doc = await db.doc(`membership/${id}`).get()
  const data = doc.data()
  if (!data) {
    console.error('member does not exist')
    return
  }
  return data
}

app.post(’/data’, cors(), async (req, res) => { const id = req.body.id if (id) { res.json(await getData(id)) return } res.end() })

这是将课程设置为已完成的API:

const setCourseAsCompleted = async (id, course) => {
  const doc = await db.doc(`membership/${id}`).get()
  const data = doc.data()
  if (!data) {
    console.error('member does not exist')
    return
  }
  if (!data[course]) {
      data[course] = {}
  }
  data[course]['done'] = true
  db.doc(`membership/${id}`).update(data)
}

app.post(’/course’, cors(), (req, res) => { const id = req.body.id const course = req.body.course if (id && course) { setCourseAsCompleted(id, course) res.end(‘ok’) return } res.end() })

基本上就是这样。还需要更多代码来处理其他逻辑,但是Firebase的要旨是我发布的代码。现在,我还可以为我的服务器端服务添加一个用户,并限制对Firebase API的所有其他访问并增强其安全性。


更多服务教程: