1 Firestore

1.1 Firestore 和 Realtime Database

Realtime DatabaseCloud Firestore
数据模式Json 树文档与集合
离线数据支持安卓、苹果安卓、苹果、Web 客户端
在线监测支持不提供原生支持
数据查询具有有限排序和过滤功能的深度查询具有复合排序和过滤的索引查询
可扩展性缩放需要分片缩放是自动的
收费仅对带宽和存储收费,但费率更高主要对**(读、写、删除)操作**收费,并以较低的费率对带宽和存储收费。

1.2 如何在 Unity 中使用 Firestore

  • 创建数据库并在 Unity 项目中集成 SDK
  • 初始化 Cloud Firestore
using Firebase.Firestore;
using Firebase.Extensions;
 
FirebaseFirestore db = FirebaseFirestore.DefaultInstance;
  • 添加数据

使用以下示例代码创建一个新集合和一个文档。

DocumentReference docRef = db.Collection("users").Document("alovelace");
Dictionary<string, object> user = new Dictionary<string, object>
{
        { "First", "Ada" },
        { "Last", "Lovelace" },
        { "Born", 1815 },
};
docRef.SetAsync(user).ContinueWithOnMainThread(task => {
        Debug.Log("Added data to the alovelace document in the users collection.");
});

现在将另一个文档添加到 users 集合中。请注意,此文档包含一个未出现在第一个文档中的键值对(中间名)。集合中的文档可以包含不同的信息集。

DocumentReference docRef = db.Collection("users").Document("aturing");
Dictionary<string, object> user = new Dictionary<string, object>
{
        { "First", "Alan" },
        { "Middle", "Mathison" },
        { "Last", "Turing" },
        { "Born", 1912 }
};
docRef.SetAsync(user).ContinueWithOnMainThread(task => {
        Debug.Log("Added data to the aturing document in the users collection.");
});
  • 读取数据

可以使用“get”方法来检索整个集合。

CollectionReference usersRef = db.Collection("users");
usersRef.GetSnapshotAsync().ContinueWithOnMainThread(task =>
{
  QuerySnapshot snapshot = task.Result;
  foreach (DocumentSnapshot document in snapshot.Documents)
  {
    Debug.Log(String.Format("User: {0}", document.Id));
    Dictionary<string, object> documentDictionary = document.ToDictionary();
    Debug.Log(String.Format("First: {0}", documentDictionary["First"]));
    if (documentDictionary.ContainsKey("Middle"))
    {
      Debug.Log(String.Format("Middle: {0}", documentDictionary["Middle"]));
    }
 
    Debug.Log(String.Format("Last: {0}", documentDictionary["Last"]));
    Debug.Log(String.Format("Born: {0}", documentDictionary["Born"]));
  }
 
  Debug.Log("Read all data from the users collection.");
});
  • 保护数据

可以在控制台的 规则选项卡 中修改您的安全规则。

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

2 Cloud Functions

2.1 Cloud Functions 简介

Cloud Functions for Firebase 是一个无服务器框架,可让您自动运行后端代码以响应由 Firebase 功能和 HTTPS 请求触发的事件。您的 JavaScript 或 TypeScript 代码存储在 Google 的云中并在托管环境中运行。无需管理和扩展您自己的服务器。

  • 关键能力
    • 集成 Firebase 平台
    • 零维护
    • 私密性与安全性
  • 触发方式
    • HTTP 请求触发

      可以通过 Http 请求触发 Function 实现诸如时间服务器、数据库搜索等功能。

    • Firebase 各类触发器触发

      通过各类 Firebase 的触发器触发函数,可以实现数据库部分字段的数值统计等功能,避免各个客户端单独执行写入操作造成的数据混乱。触发器有注入 Cloud Firestore 触发器、Authentication 触发器等。

    • 定时触发函数

    • 在应用中直接调用函数

2.2 编写、测试、部署 Cloud Functions

  • 设置 Node.js 和 Firebase CLI

Cloud Functions 支持 JavaScript 和 TypeScript,这里我们使用 JavaScript。

需要一个 Node.js 环境来编写函数,并且需要 Firebase CLI 将函数部署到 Cloud Functions。

安装 Node.js 和 npm 后,通过 npm 安装 CLI。

npm install -g firebase-tools
  • 初始化项目
  1. 运行 firebase login 以通过浏览器登录并验证 Firebase CLI。
  2. 转到您的 Firebase 项目目录。
  3. 运行 firebase init firestore
  4. 运行 firebase init functions
  • 编写函数代码

使用 Node require 语句导入 Cloud Functions 和 Admin SDK 模块。

这些行加载 firebase-functionsfirebase-admin 模块,并初始化一个可以从中进行 Cloud Firestore 更改的 admin 应用程序实例。只要 Admin SDK 支持可用,例如 FCM、身份验证和 Firebase 实时数据库,它就提供了一种使用 Cloud Functions 集成 Firebase 的强大方法。

// The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
const functions = require('firebase-functions');
 
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();

对于 addMessage() 函数,将这些行添加到 index.js

addMessage() 函数是一个 HTTP 端点。对端点的任何请求都会导致传递给 onRequest() 回调的 ExpressJS 样式的 RequestResponse 对象。

HTTP 函数是同步的(类似于 可调用函数),因此您应该尽快发送响应并使用 Cloud Firestore 推迟工作。 addMessage() HTTP 函数将文本值传递给 HTTP 端点,并将其插入路径 /messages/:documentId/original 下的数据库中。

// Take the text parameter passed to this HTTP endpoint and insert it into 
// Firestore under the path /messages/:documentId/original
exports.addMessage = functions.https.onRequest(async (req, res) => {
  // Grab the text parameter.
  const original = req.query.text;
  // Push the new message into Firestore using the Firebase Admin SDK.
  const writeResult = await admin.firestore().collection('messages').add({original: original});
  // Send back a message that we've successfully written the message
  res.json({result: `Message with ID: ${writeResult.id} added.`});
});

对于 makeUppercase() 函数,将这些行添加到 index.js

makeUppercase() 函数在写入 Cloud Firestore 时执行。 ref.set 函数定义要侦听的文档。出于性能原因,您应该尽可能具体。

大括号——例如, {documentId} ——围绕“参数”,通配符在回调中公开它们的匹配数据。

每当添加新消息时,Cloud Firestore 都会触发 onCreate() 回调。

// Listens for new messages added to /messages/:documentId/original and creates an
// uppercase version of the message to /messages/:documentId/uppercase
exports.makeUppercase = functions.firestore.document('/messages/{documentId}')
    .onCreate((snap, context) => {
      // Grab the current value of what was written to Firestore.
      const original = snap.data().original;
 
      // Access the parameter `{documentId}` with `context.params`
      functions.logger.log('Uppercasing', context.params.documentId, original);
      
      const uppercase = original.toUpperCase();
      
      // You must return a Promise when performing asynchronous tasks inside a Functions such as
      // writing to Firestore.
      // Setting an 'uppercase' field in Firestore document returns a Promise.
      return snap.ref.set({uppercase}, {merge: true});
    });
  • 测试和部署函数

Firebase Local Emulator Suite 允许您在本地计算机上构建和测试应用程序,而不是部署到 Firebase 项目。

运行此命令以部署您的函数:

 firebase deploy --only functions

运行此命令后,Firebase CLI 会输出任何 HTTP 函数端点的 URL。在您的终端中,您应该会看到如下一行:

Function URL (addMessage): https://us-central1-MY_PROJECT.cloudfunctions.net/addMessage

2.3 一些简单的 Cloud Functions 实例

可以访问下面这个 地址 来查看一些官方示例:

https://github.com/firebase/functions-samples

2.4 Cloud Functions 的一些局限性

  • 当数据库较大时,Firestore 触发会存在 1 到 2 秒的延时,对于一些高时效性数据可以选择手动写入。
  • Cloud Functions 对 Firestore 的读写也是计费的,因此需要优化函数的触发条件和内部执行方式,避免费用过高的问题。

3 小结

基于这两个系统,可以实现 Unity 的公会系统 公会系统

4 参考文档

更多内容可以查阅 FirestoreCloud Functions 的官方文档,以及一些 官方示例

  1. Firestore: https://firebase.google.com/docs/firestore?authuser=0
  2. Cloud Functions: https://firebase.google.com/docs/functions?authuser=0
  3. functions-samples: https://github.com/firebase/functions-samples