检测客户端代码中 Firestore db 节点的更改

Posted

技术标签:

【中文标题】检测客户端代码中 Firestore db 节点的更改【英文标题】:Detect changes in Firestore db node within client side code 【发布时间】:2018-11-30 09:29:34 【问题描述】:

您能告诉我如何在客户端代码(.ts 文件)中检测 Firestore db 节点的变化吗?我知道如何使用云功能做到这一点。但是如何在客户端代码中做到这一点?

Firestore 节点: projects/id/transactions/

我的要求是这样的:如果以上节点有任何变化,我需要升级提供者(即projectProvider)的共享属性值。我该怎么做?

举个例子:

onWrite 事件非常适合我的用例。但是如何在客户端.ts 文件中实现它呢?

这是node.js 云功能的实现。如何在客户端.ts 文件上进行这样的实现?

// Listen for any change on document `marie` in collection `users`
exports.myFunctionName = functions.firestore
    .document('users/marie').onWrite((change, context) => 
      // ... Your code here
    );

注意:我将angularfire2 与我的ionic 3 应用程序一起使用。

【问题讨论】:

是否有充分的理由不为此使用 Cloud Functions?您可以使用 Node 中的 Web/javascript SDK 来收听使用 onSnapshot 的集合。您也可以使用 Admin SDK 执行此操作。但是,Javascript SDK 有一个名为querySnapshot 的属性docChanges。这将允许您仅过滤已更改的文档并处理这些文档。如果这适合您的需要,我可以发布一些示例代码。 我了解云功能及其功能。但是我的用例在这里有所不同。如果firestore db有任何变化,我需要更新本地属性。所以我不能使用云功能,因为它不能访问客户端属性(.ts)。我们不能在客户端代码中调用onWrite 事件吗?我看到call functions直接方法。但它仅适用于HTTPS callable function。 @JasonBerryman firebase.google.com/docs/functions/callable 可调用函数允许您从客户端应用程序中调用函数。它们不允许您像 Cloud Functions 那样监控其他客户端对数据库的更改。如果有帮助,我可以发布一些代码,让您可以监控集合并通知您更改。 是的,请继续说。谢谢@JasonBerryman 【参考方案1】:

我的解决方案

第 1 步。 在 firestore 中,为您要通知客户端的任何信息制作通知文档。像这样的:

db.collection('notifications').doc('transactionHappened').set(/*your transaction details*/);

第 2 步。 注册到您的通知文档并收听它,例如当你在写一个交易文档时,也要将你最新的交易信息写入到transactionHappened doc中:

const yourHandler = data=>/*handle your notification details here*/;
db.collection('notifications').doc('transactionHappened').onSnapshot(yourHandler);

第 3 步。 现在 onSnapshot 已注册,但如果您的应用已断开连接,则在此期间它不会收到任何通知。让我们处理它。

const reconnectHandler =()=>/*you were offline, so read whatever you need from firestore to cath up with the latest data*/;
const disconnectHandler =()=>/*display something on your screen to indicate it is offline*/;
const monitorNetwork=()=> 
    let status = true;
    const timeout = ()=> setTimeout(()=>
        if(status !== navigator.onLine) 
            status = navigator.onLine;
            console.log(`Network is $status? 'up ?':'down ?'`);
            if (status)  //if network is flipped to online
                reconnectHandler();
             else //just went offline
                disconnectHandler();
            
        
        timeout();
    , 1000);
    timeout();

上面的小功能会每1秒为你创建一个心跳来监控你的网络状态。

【讨论】:

【参考方案2】:

部分解决方案

以下代码将允许您收听单个集合。目前没有办法跨多个项目文档收听子集合。对此的最佳解决方案是对您的数据模型进行反规范化,以便您拥有一个名为 projectTransactions 的集合,并使用 projectId 字段过滤客户端查询,并使用安全规则强制访问。

代码使用docChanges 方法,该方法允许您仅查看对集合所做的更改,而无需查看每个文档。这种方法在"View changes between snapshots" section of the documentation 中讨论过

查看查询快照之间查询结果的实际变化通常很有用,而不是简单地使用整个查询快照。

const firebase = require('firebase');
require("firebase/firestore");

// Initialize Firebase
let config = 
  apiKey: "*** Your API key ***",
  authDomain: "*** Your Auth domain ***",
  databaseURL: "*** Your database URL ***",
  projectId: "*** Your project ID ***",
  messagingSenderId: "*** Your Messaging Sender ID ***"
;
firebase.initializeApp(config);

let email = 'my.name@example.com';
let password = 'myExamplePassword';

firebase.auth().signInWithEmailAndPassword(email, password)
  .catch(error => 
    console.log(error);
  );

firebase.auth().onAuthStateChanged((user) => 
  if (user) 
    console.log('I am logged in');

    // Initialise Firestore
    const firestore = firebase.firestore();
    const settings = timestampsInSnapshots: true;
    firestore.settings(settings);

    return firestore
    .collection('projectTransactions')
    .onSnapshot((querySnapshot) => 
      console.log('Listening to the projectTransactions collection');
      querySnapshot.docChanges().forEach((change) => 

        // A new transaction has been added
        if (change.type === 'added') 
          console.log(`A new transaction has been added with ID: $change.doc.id`);
        

        // A transaction has been deleted
        if (change.type === 'removed') 
            console.log(`A transaction has been removed with ID: $change.doc.id`);
        

      );
    );

   else 
    // User is signed out.
    // ...
  
);

【讨论】:

其实这不是我需要的。我需要订阅onWrite 事件。看来我们不能通过客户端代码做到这一点? 还有change.type === 'modified'。这些change.type 属性是您可以获得的最接近的属性。

以上是关于检测客户端代码中 Firestore db 节点的更改的主要内容,如果未能解决你的问题,请参考以下文章

交易中删除的 Firestore 节点

了解 Firestore 查询

设置 Firestore 文档时如何检测不存在的网络连接

仅当 Firebase Firestore 中不存在文档时才创建文档

查询文件 ID 的 firestore 数据库

从firestore颤振提供程序中的db收集数据时如何初始化一个类