【问题标题】:How can I effectively manage the amount of observers/listeners on a document in Firebase?如何有效地管理 Firebase 文档中观察者/听众的数量?
【发布时间】:2020-05-09 08:10:17
【问题描述】:

假设我在 Cloud Firestore 中有一组文档。我希望人们观察这些文件,但我不希望超过 100 人在任何时间点观察同一份文件。我如何有效地跟踪这一点?

我最初考虑通过管理每个文档中的一组用户 ID 来跟踪观察者/听众的数量。实际上,用户会在观察/收听之前将他们的 ID 添加到这个数组中(或者如果这个数组太大则被拒绝),并在他们停止时从这个数组中删除他们的 ID。这样做的问题是,如果从数组中删除此 ID 的调用失败,我不能仅仅阻止用户离开。如果他们以某种方式终止了应用程序并且删除他们的 ID 的调用没有通过怎么办?

这个问题有更合理的解决方案吗?这可以通过实时数据库或云函数解决吗?谢谢!

【问题讨论】:

  • 您是否看过documentation 在 Cloud Firestore 中构建在线状态系统?但是,即使您维护一组“在场”或“聆听”的人,我也看不出如何避免有人对您的应用程序进行逆向工程并设置侦听器而不检查您在问题中提到的数组(或任何类似的存在系统等机制)。换句话说,解决方案必须在后端恕我直言。 Cloud Functions 可能会有所帮助,但请注意,如果您计划通过 Cloud Functions 读取数据,则会失去实时功能。
  • 这个文档不是我找到的,但它真的很有趣。我会测试它的实现,直到出现更好的解决方案。谢谢!!!
  • 看来,要使用这种方法,每个观察文档的人都需要有一个持续的并发连接。看到并发连接上限,如果存在,我更喜欢不同的解决方案。编辑:我刚刚找到了有关分片的信息,为此提供了解决方案
  • 这可能太简单了,但是您可以添加另一个节点来跟踪有多少观察者正在观察特定节点吗? observer_counts 作为父节点,然后是子节点 node_0: current_observer_count,然后是 node_1: current_observer_count。当您要添加观察者时,请检查计数以查看是否
  • 这是我最初想法的一个版本,但缺陷是我们不能假设更改数据库的调用会成功。因此,可能会出现用户失去连接或应用程序提前终止的情况,以至于从数据库中删除观察者的调用失败并且数据库反映了不正确的信息。可以说这是罕见的情况,但是。事实上,我不知道它有多罕见,而且我的应用无法反映这种形式的错误数据。

标签: swift firebase firebase-realtime-database google-cloud-firestore google-cloud-functions


【解决方案1】:

我不确定,但请尝试用 Google 搜索 Firebase 访问规则。我认为您可以管理此范围内的访问。
我讲这个规则。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}

抱歉以这种方式回答,我没有创建 cmets 所需的声誉

【讨论】:

  • 您好,我认为这不能回答 OP 问题。您的示例展示了如何向任何用户授予读写访问权限,但不限制“在任何时间点观察同一文档的人”的数量。
  • 我同意 Tarnec 的说法。我不明白这如何解决我的问题,但我非常感谢您的回复!
【解决方案2】:

已解决!非常感谢 Renaud Tarnec 的原始评论引用了我尚未看到的文档。我在 Google 搜索中遗漏了关键字“存在”。如果您觉得这个答案有帮助,请点赞他的评论!

解决方案:使用https://firebase.google.com/docs/firestore/solutions/presence

斯威夫特:

var connectionReference: DatabaseReference = Database.database().reference(withPath: ".info/connected")
var personalReference: DatabaseReference?
var connectionIssued: Bool = false
func connect(room: String) {
    // Remove any existing observations to ensure only one exists.
    connectionReference.removeAllObservers()
    // Start observing connection.
    connectionReference.observe(.value) { (isConnected) in
        if isConnected.value as! Bool {
            // Connected!
            // Use Bool connectionIssued to ensure this is run only once.
            if !self.connectionIssued {
                self.connectionIssued = true
                self.personalReference = Database.database().reference(withPath: "OnlineUsers/\(userID)")
                // Set onDisconnect before setting value.
                self.personalReference!.onDisconnectRemoveValue()
                self.personalReference!.setValue(room)
                // Now the user is "online" and can proceed.
                // Allow user to "enter" room.
            } else {
                // Connection already issued.
            }
        } else {
            // The user has either disconnected from an active connection or they were already disconnected before connect() was called.
            // Stop observing connection.
            self.connectionReference.removeAllObservers()
            // If the user disconnects after they have entered a room, kick them out.
            if self.connectionIssued {
                // User lost connection.
                kickUserOutOfRoom()
                self.connectionIssued = false
            } else {
                // User cannot log in.
            }
        }
    }
}
// Call when users leave a room when still connected.
func leaveRoomManually() {
    // Remove connection observation.
    connectionReference.removeAllObservers()
    // Attempt to remove "online" marker in database.
    personalReference?.removeValue(completionBlock: { (error, reference) in
        if error != nil {
            // Removal failed, but that should be okay!
            // onDisconnect will still be called later!
            // This failure might result in ghost users if the user proceeds to join another room before disconnecting.
            // Consider writing an onUpdate() cloud function in conjunction with the following onCreate() and onDelete() cloud functions to take care of that case.
        } else {
            // "Online" marker removed from database!
            // We can now cancel the onDisconnect()
            self.personalReference?.cancelDisconnectOperations()
        }
    })
    leaveRoom()
}

云函数(javascript):

以下云函数会更新 Cloud Firestore 中各个房间的客人人数。

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

const firestore = admin.firestore();
exports.userCameOnline = functions.database.ref('/OnlineUsers/{userID}').onCreate(
    async (snapshot, context) => {
        const room = snapshot.val();
        const guestCountRef = firestore.doc(`Rooms/${room}`);
        return guestCountRef.update({
            Guests: admin.firestore.FieldValue.increment(1)
        });
    });
exports.userWentOffline = functions.database.ref('/OnlineUsers/{userID}').onDelete(
    async (snapshot, context) => {
        const room = snapshot.val();
        const guestCountRef = firestore.doc(`Rooms/${room}`);
        return guestCountRef.update({
            Guests: admin.firestore.FieldValue.increment(-1)
        });
    });

【讨论】:

    猜你喜欢
    • 2015-02-19
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    • 2019-06-09
    相关资源
    最近更新 更多