筆記:Firebase functions with authentication

主要可以 trigger 兩個,一個是 onCreate,一個是 onDelete

onCreate 在以下情況會被觸發

  • A user creates an email account and password.
  • A user signs in for the first time using a federated identity provider.
  • The developer creates an account using the Firebase Admin SDK.
  • A user signs in to a new anonymous auth session for the first time.
exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => {
  // ...
});


onDelete 在使用者被刪除時觸發

exports.sendByeEmail = functions.auth.user().onDelete((user) => {
  // ...
});

裡面的 user 主要就是 UserRecord

email / displayName / customClaims / uid / …. 等欄位都有。

onDelete 可以用來做刪除 firestore/realtime database 上的資料,需要考慮 functions 能執行多久。

筆記:Queries, Part 1: Common SQL Queries Converted for Firebase

依照 Queries, Part 1: Common SQL Queries Converted for Firebase 來練習

  • By ID ,路徑指定好就可以了 firebase.database().ref(‘/messages/’ + messageID).once(‘value’, function(snap) { … });
  • WHERE, 除了路徑之外,還要指定 orderByKey() 或 orderByChild(),然後再用 startAt/endAt
    • orderByKey 是依照 key 的值:firebase.database().ref(‘/messages’).orderByKey().startAt(‘user001’).endAt(‘user010’).once(‘value’, function(snap) { … });
    • orderByChild 是依照子節點的值:firebase.database().ref(‘/messages’).orderByChild(’email’).startAt(‘user001@example.com’).endAt(‘user010@example.com’).once(‘value’, function(snap) {…});
    • 用 orderByChild 時,要在規則裡加上 .indexOn ,否則會有警告,警告的大意是說加indexOn 後,效能會比較好。
  • LIMIT,加 limitToFirst(10) 或 limitToLast(10)
    • 可以跟前面提到的 startAt / endAt 結合:firebase.database().ref(‘/messages’).orderByChild(’email’).startAt(‘user001@example.com‘).endAt(‘user010@example.com‘).limitToFirst(10).once(‘value’, function(snap) {…});
    • limitToLast 就是指定後面幾筆

筆記:firebase functions – realtime database

閱讀的文件:https://firebase.google.com/docs/functions/database-events

可以寫這些事件的處理常式

  • onWrite() 資料被建立、更新或刪除時,會觸發
  • onCreate() 資料被建立時,會觸發
  • onUpdate() 資料被更新時,會觸發
  • onDelete() 資料被刪除時,會觸發

可以只針對指定的路徑,對,也因為事件資料同時包含舊的跟新的,資料量有限制,資料量大的時候要針對個別路徑拆開來寫處理常式。

可以用參數,例如 ref(‘foo/{bar}’)  ,那麼存取 foo/hello 或 foo/firebase 時,都會觸發常式對 foo/ 寫入,像下面

{
  "foo": {
    "hello": "world",
    "firebase": "functions"
  }
}

會觸發兩次常式,一次是 foo/hello ,一次是 foo/firebase從 EventContext.params 可以用 bar 這個 key 去拿到 hello 或 firebase
範例

 
// 當有訊息加到 /messages/:pushId/original 時,執行這常式。 
// 這常式會把指定路徑下的值,轉為大寫,再放到 /messages/:pushId/uppercase 
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original') 
    .onCreate((snapshot, context) => {  // snapshot 是 DataSnapshot ,context 是 EventContext 
      // 先取得寫入的值 
      const original = snapshot.val(); 
      console.log('Uppercasing', context.params.pushId, original); 
      const uppercase = original.toUpperCase(); 
      // 把資料寫到 "uppercase" sibling 然後回傳 Promise 
      // snapshot.ref.parent -> /messages/:pushId 
      // snapshot.ref.parent.child('uppercase') -> /messages/:pushId/uppercase 
      return snapshot.ref.parent.child('uppercase').set(uppercase); 
    }); 

用 EventContext 的 auth / authType 就可以取得 authentication 資訊 (這邊我有點迷糊了,為啥 authType 可以是 ADMIN / USER ??

onWrite 的時候,是用 change, context change 是 Change,提供了 before/after property 可以存取寫之前/之後的值 。

筆記:Best practics for firebase realtime database development

文章出處:Best practics for firebase realtime database development

以下只是摘要,詳細內容還是請看原文。

  • 好好的讀 SDK 文件。
  • 不太需要定 schema,不表示不需要用腦,要有效率的使用,仍然需要好好的規劃。
  • 支援管道要選好
    • Slack: 社群導向的自助討論,不適合回報問題。
    • Support Form: 主要的官方支援,The “official” support venue. Report “something is down” here. Feature requests likely to get a canned “we’ll consider it, but no promises” response.
    • Google Groups: 主要是成員討論,Active involvement by the core team with the usual caveats about turnaround time in group-oriented mail systems. Best place for highly technical discussions about app internals and “weird” issues.
    • StackOverflow: 疑難雜症,Slow/unpredictable response times but best place for backup reference material. If you’ve read a Q&A on StackOverflow, you know the type of question that’s best to post there, too.
  • 該用兩個 reference 就用,不要想說用他們共通的父節點來存取,這樣沒有比較省。If you need to reference an object from two different places, take two refs to it.
  • 不要用 array
  • 沒有日期,請用 timestamp
  • 請知道 firebase realtime database 能做什麼,不要用他來做他不適合做的事情。
  • set 跟 update 不一樣,主要差異是在於 key 存在與否的處理。
  • firebaseui 很好用。

Firebase functions 裡用 Admin SDK 時,怎麼去把設定跟程式切開?

一般來說,照文件來做,會要放兩個設定,第一個是 Service account credential,第二個是 Firebase config。

但其實在部署 functions 上去以後,這些設定都已經在執行環境裡了,所以不需要特別去放這些設定。而且,把這些設定放到程式裡,那程式會上到 git repository 啊,這樣設定就都曝光了。那不想把這些設定放到程式裡,本地端又要開發時該怎麼辦呢?我是找到這篇:Firebase: Separating configuration from code in Admin SDK

第一個,Service account credential 在下載以後,假設放到 /credentials/your_service_account.json,那麼在執行前,把這檔案路徑指定到 GOOGLE_APPLICATION_CREDENTIALS 這環境變數就可以,例如:

export GOOGLE_APPLICATION_CREDENTIALS=/credentials/your_servcice_account.json

第二個是 Firebase config,從 firebase console 取得以後,假設放到 /config/your_project_config.json ,裡面內容大致是

{
apiKey: "your_api_key",
authDomain: "your_project.firebaseapp.com",
databaseURL: "https://your_project.firebaseio.com",
projectId: "your_project-abcdef",
storageBucket: "your_project.appspot.com",
messagingSenderId: "00000000",
appId: "1:00000000:web:000000000",
measurementId: "G-11111111"
};

接著一樣去設定環境變數 FIREBASE_CONFIG

export FIREBASE_CONFIG=/config/your_project_config.json

然後就可以使用 firebase serve 去模擬啦。

筆記:Lessons learnt (the hard way) using Firebase RealTime Database

主要是看這篇 Lessons learnt (the hard way) using Firebase RealTime Database 所摘要下來的重點。

TL;DR:作者用了 realtime database,然後意外收到 1000 EUR 的帳單。

作者做的是交通運輸類的 app ,realtime database 存的是使用者的最愛站牌、路線等。主要用了 Firebase 的這兩項功能:

  • Firebase authentication
  • Realtime database

使用人數約 400K+ ,主要就是 updated / authenticated 等等的。這樣帳單約 1000 EUR
他們檢討以後,發現有幾個關鍵點:

  1. keepSync ,這個不要設成 true,firebase SDK的行為沒有預期中聰明,他會在每次使用者開啟app時就下載一次!
    1. database.getReference(getUserFavoritesPath(getCurrentUid())).keepSynced(true)
  2. key 的名稱不要太長,只要這個弄短,無形中可以省掉非常多。

接著針對這兩個點,做了處理

  1. 最佳化存在資料庫的資料,改用 GSON ,以及縮短 key 的長度。
  2. 關掉 keepSync
  3. 在 app 端實作了 memory cache ,以避免無謂的去 firebase 撈資料。

作者學到的事情:

  1. 人數很多時,realtime database 可能會是很花錢的項目,特別是結構跟讀取資料邏輯沒有最佳化的時候。
  2. 要將存在雲端上的資料最小化,使用較短長度的 key ,可以幫你省掉不少錢。
  3. Firebase persistence 啟用時,firebase 只會在沒網路的時候使用本地的 cache,其他的狀況他不管資料有沒有改都會存取雲端。
  4. 不要用 keepSync(true) 
  5. 實作本地端的 cache ,以避免重複跟 firebase 索取資料。