Firebase limit on the number of observers/listeners
There is no limit on the number of listeners that may be attached from one client. Also note that listeners are generally inexpensive, so it is recommended that you use them as most convenient in your application.
How can I effectively manage the amount of observers/listeners on a document in Firebase?
SOLVED! Big thanks to Renaud Tarnec for his original comment referencing documentation I had not yet seen. I was missing the keyword 'presence' in my Google searches. Please upvote his comment if you find this answer helpful!
SOLUTION: Using https://firebase.google.com/docs/firestore/solutions/presence
SWIFT:
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()
}
CLOUD FUNCTIONS (javascript):
The following cloud functions update the respective room's guest count in 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)
});
});
Firebase simultaneous connection limit if adding more listeners
The number of connections to Realtime Database is almost certainly not going to be related to the types of data you're storing, or the way that data is organized.
Every mobile client establishes exactly one websocket to Realtime Database, and that socket is only active when the app is running in the foreground (and maybe a bit outside of that in some cases). That socket is considered a single connection, and all traffic between the database and the client go over that socket. It doesn't matter what data is being transferred - there is only that one socket.
Don't confuse listeners with connections. All added listeners/observers in an app use the same socket. Reducing the number of listeners will not reduce the number of connections.
Firebase limit on the number of nodes/data returned in Snapshot
Firebase will "return" all child nodes, unless you explicitly limit the number of nodes with queryLimitedToFirst:
or queryLimitedToLast:
. See the section of the Firebase documentation on queries for some good examples of these.
One thing to constantly keep in mind when working with Firebase is that you're not just querying the data source, you're actively synchronizing, listening for changes as they happen. Say for example that you have a Firebase that contains status updates from you and your friends. And you have a page that shows the latest 10 updates.
- Set up a query ordered by timestamp (a field in your status updates) with
queryOrderedByChild
. - Limit the query to latest 10 updates with
queryLimitedToLast:
. - You will receive 10
FEventTypeChildAdded
events (assuming that there are at least that many status updates). - A friend posts a new status update.
- Your page will receive a
FEventTypeChildRemoved
for the oldest status update and aFEventTypeChildAdded
for the new status update.
Is it acceptable to have many 'WHERE' based listeners
You'll have to be more specific about "bazillion". In general, listeners are cheap and you shouldn't worry too much about it. But everything has a practical limit, and I think you'll discover what that is as you approach your hypothetical "bazillion".
1 listener doesn't invoke billing any different than 10 or 100 or 1000 listeners. You can expect the billing for a single listener to scale linearly. Each one will cost exactly what it would normally cost on its own, for each document that is different between all their queries.
Each listner also shares a single connection, so you don't have to worry about running out of open file descriptors or anything like that. Your limit is, practically speaking, going to be memory and bandwidth.
Is it a good practice to have big number of childEventListeners?
Yes you can have multiple ChildEventListeners is it a good practice no. You should really use one and have a LinkedHashMap type structure so that you can allocate your data to a certain Key which you can then call back later on.
Check if I have an observer listening in firebase swift
I could not find a firebase api to achieve this. I solved it using this workaround
var handle = ref.child("child").observe()
// check if nil before detaching listener
guard self.handle != nil else { return }
self.ref.removeObserver(withHandle: self.handle)
Related Topics
Changed +Load Method Order in Xcode 7
Create and Perform Segue Without Storyboards
Swiftui Landmarks App Tutorial Screen Navigates Back When Toggle Favorite
Multiline Label in Uistackview
iOS 11 Safe Area Layout Guide Backwards Compatibility
How to Hide "-" (Delete) Button While Editing Uitableview
Xcode 6 Storyboard Unwind Segue with Swift Not Connecting to Exit
Apn (Apple Push Notification) Payload Size Limit
iOS 11 Large-Title Navigation Bar Not Collapsing
How to Play Video Stream with Mpmovieplayercontroller in iOS
Hide Device Volume Hud View While Adjusitng Volume with Mpvolumeview Slider
Have a Variable with Multiple Types in Swift
How to Invoke iPhone Maps for Directions with Current Location as Start Address
Contentview Not Indenting in iOS 6 Uitableviewcell Prototype Cell
How to Find Out Distance Between Coordinates
Exc_Bad_Instruction (Code=Exc_I386_Invop, Subcode=0X0) on Dispatch_Semaphore_Dispose