将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的所有其他访问并增强其安全性。
更多服务教程:
- 如何开始使用Firebase托管
- 在Netlify上托管静态站点的教程
- Web开发人员的代码插入程序和格式化程序
- 自动触发器部署在Netlify上
- Glitch,一个伟大的开发人员平台
- 适用于开发人员的Airtable API
- 如何通过任何Google API进行身份验证
- Zeit Now教程
- Netlify Lambda函数教程
- 如何将Firebase Firestore用作数据库
- 我如何修复Netlify重写中的结尾斜杠
- 如何在Netlify函数中访问查询参数
- 如何在Netlify函数中使用环境变量
- 如何在Netlify函数中使用npm软件包
- 如何在DigitalOcean上创建第一个VPS