Firebase 教學 - Node.js 操作 Firestore

當我們可以透過 Node.js 在後端運行 Firebase 之後,就能完成許多好玩的應用,這篇文章將會描述如何透過 Node.js 操作 Firestore,最後還會把程式碼部署到 Google Cloud functions,實現透過 http request 串接 Firestore 的應用範例。

延伸閱讀:

安裝 Node.js 相關模組

Firestore 在 Node.js 裡的用法跟網頁前端大同小異,在網頁前端僅需載入對應的 JavaScript,而 Node.js 裏頭僅需引用對應的模組即可,安裝套件的指令如下,首先建立並初始化一個 Node.js 專案。

$ npm init

接著安裝 firebase 模組以及 firestore 模組。

注意,Firestore 模組必須運行在 Node.js 10 以上的版本,可以透過 nvm 進行 Node.js 的版本更新。

$ npm install --save @google-cloud/firestore

使用時 require firestore 模組,宣告一個變數進行 firestore 初始化,並設定 Firestore 的 Project ID。

const Firestore = require('@google-cloud/firestore');
const firestore = new Firestore({
    projectId: 'XXXXXXX'
});

然而 Firestore 並沒有像 Realtime Database 那樣的方便 ( 換句話說就是安全性較低 ),如果要使用 Node.js 操作,還得具備指定的金鑰才能正常運行,申請金鑰很簡單,進入 Google Cloud Platform,選擇 Firestore 的專案 ( 專案名稱就是建立 Firestore 時的專案名稱 ),左側選單選擇「API 和服務 > 憑證 > 建立憑證」,點選 「服務帳戶金鑰」。

進入後下拉選單選擇「App Engine default service account」,金鑰類型選擇「json」。

點選建立後會下載一個 json 檔案,將這個 json 檔案和操控 Firestore 的 Node.js 放在相同目錄下,基本的 Firestore 設定就差不多完成了,可以開始撰寫 Node.js 程式。

透過 http request 操作 RealTime Database

透過 Node.js 內建的http 模組,可以建立個接收 http request 的 server,搭配內建的url 模組,就能將收到的資料訊息轉換為物件格式,比較需要注意的地方有兩個:

下方的程式碼執行後,就會啟動一個本地端的 server,這時只要在網址列輸入https://網址?projectid=XXX&type=set&data=XXX就能將資料寫入到預設 collection 為 default、doc 名稱為 default 的資料庫裡,在網址列輸入http://網址?XXX&type=get就能讀取 collection 為 default 的資料庫資料。

此處我的 Firestore 資料庫使用「Firebase 教學 - Node.js 操作 Realtime Database」一文中的資料庫。

const http = require('http');
const url = require('url');
const Firestore = require('@google-cloud/firestore');

const server = http.createServer((req, res) => {
if (req.url !== '/favicon.ico') {  // 因接收時會一併取得 undefined 的 facicon.ico,使用簡單的邏輯排除
    const params = url.parse(req.url, true).query; // 取得網址每個參數
    const collection = params.collection || 'default';
    const doc = params.doc || 'default';
    let data;
    if(params.data){
    data = JSON.parse(params.data);
    }
    const type = params.type;

    const firestore = new Firestore({
    projectId: params.projectid,
    keyFilename: 'key.json' // 放入金鑰 json
    });
    const ref = firestore.collection(collection).doc(doc);

    switch (type) {  // 依據不同的參數寫入或讀取資料
    case 'set':
        ref.set(data).then(() => {
        res.end(`set data to "${doc}" ok`);
        });
        break;
    case 'add':
        ref.add(data).then(() => {
        res.end(`add data to "${doc}" ok`);
        });
        break;
    case 'get':
        firestore.collection(collection).get().then(e => {
        let html = '';
        e.forEach(d => {
            html = `${html}<div>${d.id} : ${d.data().total} / ${d.data().good}</div>`;
        });
        res.end(html);
        });
        break;
    }
}
});
server.listen(5000);

部署到 Google Cloud Functions

已經能在本地端運行 Node.js 服務並操作 Firestore 之後,下一步就是將這組程式部署到 Google Cloud Functions 裡,登入 Google 並進入 GCP ( Google Cloud Platform ) 後,在右方選單選擇 Cloud Functions。

請先參考我的這篇文章:簡易後端實作 ( Google Cloud Functions )

建立一個專案,專案建立後就新建一組函式,輸入函式名稱以及選擇 128 MB 記憶體。

Firestore 因為有一個金鑰的 json 檔案,因此無法像 Realtime Database 一樣直接在 Cloud functions 裡頭撰寫程式碼,所以這邊選擇「zip 檔」的方式上傳壓縮檔,並選擇 Node.js 10 ( Beta 版 ),又因為得上傳程式碼,所以先將剛剛我們在本地端運行的 Node.js 程式修改成下面這樣以符合 Cloud Functions 的撰寫原則。

const url = require('url');
const Firestore = require('@google-cloud/firestore');

exports.helloWorld = (req, res) => {

    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Request-Method', '*');
    res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
    res.setHeader('Access-Control-Allow-Headers', '*');

    if (req.url !== '/favicon.ico') {
        const params = url.parse(req.url, true).query;
        const collection = params.collection || 'default';
        const doc = params.doc || 'default';
        let data;
        if(params.data){
        data = JSON.parse(params.data);
        }
        const type = params.type;

        const firestore = new Firestore({
        projectId: params.projectid,
        keyFilename: 'key.json'
        });
        const ref = firestore.collection(collection).doc(doc);

        switch (type) {
            case 'set':
                ref.set(data).then(() => {
                res.end(`set data to "${doc}" ok`);
                });
                break;
            case 'add':
                ref.add(data).then(() => {
                res.end(`add data to "${doc}" ok`);
                });
                break;
            case 'get':
                firestore.collection(collection).get().then(e => {
                let html = '';
                e.forEach(d => {
                    html = `${html}<div>${d.id} : ${d.data().total} / ${d.data().good}</div>`;
                });
                res.end(html);
                });
                break;
        }
    }

};

修改 package.json 的內容,讓部屬時會自動安裝 firebase 模組。

{
    "name": "firestore",
    "version": "0.0.1",
    "dependencies": {
        "@google-cloud/firestore": "^2.2.4"
    }
}

最後將 index.js、package.json 和 key.json 放在同一個資料夾,並用加縮軟體壓縮成 zip 檔。

因為要上傳 zip 檔案到 GCP,所以要額外設定 Bucket 的資料夾名稱,這也是 GCP 的雲端儲存空間的服務之一,設定好 Bucket 的名稱後就可以上傳。

上傳完成後按下「建立」,就會開始部署程式,部署成功會看見函式前方出現綠色的勾勾圖示,在觸發條件的頁籤裡也會看見最終部署的網址。

在瀏覽器輸入網址並後方加上參數,執行後就會寫入資料到資料庫,或是從資料庫讀取資料囉~

小結

透過 Node.js 搭配 Google Cloud Functions,就能輕鬆實現透過 http request 存取 Firestore 的功能囉~

有興趣瞧瞧其他新文章嗎?