개발하는 앱 유형에 따라 어떠한 사용자 또는 기기가 현재 온라인
상태인지를 확인하면 유용할 수 있습니다. 이러한 기능을 '접속 상태'
감지라고 합니다.
예를 들어 소셜 네트워크와 같은 앱을 빌드하거나 여러 IoT 기기를 배포할 경우 이 정보를 사용하여 채팅 가능한 온라인 상태인 친구 목록을 표시하거나 IoT 기기를 '최종 접속 시간' 순으로 정렬할 수 있습니다.
Cloud Firestore는 기본적으로 접속 상태를 지원하지 않지만 다른 Firebase 제품을 활용하여 접속 상태 시스템을 빌드할 수 있습니다.
솔루션: Cloud Functions 및 실시간 데이터베이스
Firebase 실시간 데이터베이스의 기본 접속 상태 기능에 Cloud Firestore를 연결하려면 Cloud Functions를 사용합니다.
실시간 데이터베이스를 사용하여 연결 상태를 보고한 후 Cloud Functions를 사용하여 이 데이터를 Cloud Firestore에 미러링합니다.
실시간 데이터베이스에서 접속 상태 사용
먼저 실시간 데이터베이스의 기본 접속 상태 시스템을 살펴보겠습니다.
웹
// Fetch the current user's ID from Firebase Authentication.varuid=firebase.auth().currentUser.uid;// Create a reference to this user's specific status node.// This is where we will store data about being online/offline.varuserStatusDatabaseRef=firebase.database().ref('/status/'+uid);// We'll create two constants which we will write to // the Realtime database when this device is offline// or online.varisOfflineForDatabase={state:'offline',last_changed:firebase.database.ServerValue.TIMESTAMP,};varisOnlineForDatabase={state:'online',last_changed:firebase.database.ServerValue.TIMESTAMP,};// Create a reference to the special '.info/connected' path in // Realtime Database. This path returns `true` when connected// and `false` when disconnected.firebase.database().ref('.info/connected').on('value',function(snapshot){// If we're not currently connected, don't do anything.if(snapshot.val()==false){return;};// If we are currently connected, then use the 'onDisconnect()' // method to add a set which will only trigger once this // client has disconnected by closing the app, // losing internet, or any other means.userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function(){// The promise returned from .onDisconnect().set() will// resolve as soon as the server acknowledges the onDisconnect() // request, NOT once we've actually disconnected:// https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect// We can now safely set ourselves as 'online' knowing that the// server will mark us as offline once we lose connection.userStatusDatabaseRef.set(isOnlineForDatabase);});});
전역적으로 Cloud 함수로 사용하여 Cloud Firestore에 액세스하는 다른 모든 기기에서 이 특정한 기기가 오프라인 상태임을 파악하도록 합니다.
Cloud Firestore의 로컬 캐시 업데이트
첫 번째 문제, 즉 Cloud Firestore의 로컬 캐시 업데이트를 해결하는 데 필요한 변경사항을 살펴보겠습니다.
웹
// ...varuserStatusFirestoreRef=firebase.firestore().doc('/status/'+uid);// Firestore uses a different server timestamp value, so we'll // create two more constants for Firestore state.varisOfflineForFirestore={state:'offline',last_changed:firebase.firestore.FieldValue.serverTimestamp(),};varisOnlineForFirestore={state:'online',last_changed:firebase.firestore.FieldValue.serverTimestamp(),};firebase.database().ref('.info/connected').on('value',function(snapshot){if(snapshot.val()==false){// Instead of simply returning, we'll also set Firestore's state// to 'offline'. This ensures that our Firestore cache is aware// of the switch to 'offline.'userStatusFirestoreRef.set(isOfflineForFirestore);return;};userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function(){userStatusDatabaseRef.set(isOnlineForDatabase);// We'll also add Firestore set here for when we come online.userStatusFirestoreRef.set(isOnlineForFirestore);});});
이제 애플리케이션이 자신의 온라인 접속 상태를 올바르게 보고합니다. 하지만 '오프라인' 상태 쓰기는 로컬에서만 수행되고 연결이 복원될 때 동기화되지 않으므로 다른 Cloud Firestore 앱에서는 이 상태가 아직 정확하게 보고되지 않습니다. 이 문제를 해결하기 위해 실시간 데이터베이스의 status/{uid} 경로를 감시하는 Cloud 함수를 사용합니다. 실시간 데이터베이스에서 값이 변경되면 Cloud Firestore에 값이 동기화되므로 모든 사용자의 상태가 올바르게 인식됩니다.
Node.js
firebase.firestore().collection('status').where('state','==','online').onSnapshot(function(snapshot){snapshot.docChanges().forEach(function(change){if(change.type==='added'){varmsg='User '+change.doc.id+' is online.';console.log(msg);// ...}if(change.type==='removed'){varmsg='User '+change.doc.id+' is offline.';console.log(msg);// ...}});});
이 함수를 배포하면 Cloud Firestore에서 실행되는 완전한 접속 상태 시스템이 완성됩니다. 다음은 where() 쿼리를 사용하여 온라인 또는 오프라인 상태로 전환하는 모든 사용자를 모니터링하는 예시입니다.
웹
firebase.firestore().collection('status').where('state','==','online').onSnapshot(function(snapshot){snapshot.docChanges().forEach(function(change){if(change.type==='added'){varmsg='User '+change.doc.id+' is online.';console.log(msg);// ...}if(change.type==='removed'){varmsg='User '+change.doc.id+' is offline.';console.log(msg);// ...}});});
실시간 데이터베이스를 사용하여 Cloud Firestore 앱에 접속 상태를 추가하는 방법은 확장 가능하고 효율적이지만 몇 가지 제한사항이 있습니다.
디바운싱 - Cloud Firestore에서 실시간 변경사항을 리슨하는 경우 이 솔루션은 여러 변경사항을 트리거할 수 있습니다. 이러한 변경사항으로 인해 이벤트가 너무 많이 트리거되면 Cloud Firestore 이벤트를 수동으로 디바운싱합니다.
연결 - 이 구현에서는 Cloud Firestore가 아닌 실시간 데이터베이스에 대한 연결을 측정합니다. 각 데이터베이스에 대한 연결 상태가 동일하지 않으면 이 솔루션은 정확하지 않은 접속 상태를 보고할 수 있습니다.
Android - Android에서 실시간 데이터베이스는 비활성 상태가 60초간 지속되면 백엔드에서 연결을 끊습니다. 비활성 상태란 열린 상태의 리스너나 대기 중인 작업이 없다는 의미입니다. 연결을 열린 상태로 유지하려면 값 이벤트 리스너를 .info/connected 외의 경로에 추가하는 것이 좋습니다. 예를 들어 각 세션 시작 시 FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced()를 실행하는 방법이 있습니다. 자세한 내용은 연결 상태 감지를 참조하세요.
[null,null,["최종 업데이트: 2025-08-16(UTC)"],[],[],null,["\u003cbr /\u003e\n\nDepending on the type of app you're building, you might find it useful to detect\nwhich of your users or devices are actively online --- otherwise known as\ndetecting \"presence.\"\n\nFor example, if you're building an app like a social network or deploying a\nfleet of IoT devices, you could use this information to display a list of\nfriends that are online and free to chat, or sort your IoT devices by\n\"last seen.\"\n\nCloud Firestore doesn't natively support presence, but you can\nleverage other Firebase products to build a presence system.\n\nSolution: Cloud Functions with Realtime Database\n\nTo connect Cloud Firestore to Firebase Realtime Database's native\npresence feature, use Cloud Functions.\n\nUse Realtime Database to report connection status, then use Cloud Functions to\nmirror that data into Cloud Firestore.\n\nUsing presence in Realtime Database\n\nFirst, consider how a traditional presence system works in Realtime Database. \n\nWeb \n\n```javascript\n// Fetch the current user's ID from Firebase Authentication.\nvar uid = firebase.auth().currentUser.uid;\n\n// Create a reference to this user's specific status node.\n// This is where we will store data about being online/offline.\nvar userStatusDatabaseRef = firebase.database().ref('/status/' + uid);\n\n// We'll create two constants which we will write to \n// the Realtime database when this device is offline\n// or online.\nvar isOfflineForDatabase = {\n state: 'offline',\n last_changed: firebase.database.ServerValue.TIMESTAMP,\n};\n\nvar isOnlineForDatabase = {\n state: 'online',\n last_changed: firebase.database.ServerValue.TIMESTAMP,\n};\n\n// Create a reference to the special '.info/connected' path in \n// Realtime Database. This path returns `true` when connected\n// and `false` when disconnected.\nfirebase.database().ref('.info/connected').on('value', function(snapshot) {\n // If we're not currently connected, don't do anything.\n if (snapshot.val() == false) {\n return;\n };\n\n // If we are currently connected, then use the 'onDisconnect()' \n // method to add a set which will only trigger once this \n // client has disconnected by closing the app, \n // losing internet, or any other means.\n userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function() {\n // The promise returned from .onDisconnect().set() will\n // resolve as soon as the server acknowledges the onDisconnect() \n // request, NOT once we've actually disconnected:\n // https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect\n\n // We can now safely set ourselves as 'online' knowing that the\n // server will mark us as offline once we lose connection.\n userStatusDatabaseRef.set(isOnlineForDatabase);\n });\n});https://github.com/firebase/functions-samples/blob/c4fde45b65fab584715e786ce3264a6932d996ec/Node-1st-gen/presence-firestore/public/index.js#L19-L62\n```\n\nThis example is a complete Realtime Database presence system. It handles\nmultiple disconnections, crashes and so on.\n\nConnecting to Cloud Firestore\n\nTo implement a similar solution in Cloud Firestore use the same\nRealtime Database code, then use Cloud Functions to keep Realtime Database and\nCloud Firestore in sync.\n\nIf you haven't already, add [Realtime Database](https://firebase.google.com/docs/database/) to your project\nand include the above presence solution.\n\nNext you'll synchronize the presence state to Cloud Firestore through\nthe following methods:\n\n1. Locally, to the offline device's Cloud Firestore cache so that the app knows it's offline.\n2. Globally, using a Cloud Function so that all other devices accessing Cloud Firestore know this specific device is offline.\n\n| **Note:** Remember that whenever you lose internet connectivity, you have no way to synchronize data, so you must write the same data to the same location, as shown in the following examples. This is necessary to ensure all devices receive the change in online status.\n\nUpdating Cloud Firestore's local cache\n\nLet's take a look at the changes required to fulfill the first issue - updating\nCloud Firestore's local cache. \n\nWeb \n\n```javascript\n// ...\nvar userStatusFirestoreRef = firebase.firestore().doc('/status/' + uid);\n\n// Firestore uses a different server timestamp value, so we'll \n// create two more constants for Firestore state.\nvar isOfflineForFirestore = {\n state: 'offline',\n last_changed: firebase.firestore.FieldValue.serverTimestamp(),\n};\n\nvar isOnlineForFirestore = {\n state: 'online',\n last_changed: firebase.firestore.FieldValue.serverTimestamp(),\n};\n\nfirebase.database().ref('.info/connected').on('value', function(snapshot) {\n if (snapshot.val() == false) {\n // Instead of simply returning, we'll also set Firestore's state\n // to 'offline'. This ensures that our Firestore cache is aware\n // of the switch to 'offline.'\n userStatusFirestoreRef.set(isOfflineForFirestore);\n return;\n };\n\n userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function() {\n userStatusDatabaseRef.set(isOnlineForDatabase);\n\n // We'll also add Firestore set here for when we come online.\n userStatusFirestoreRef.set(isOnlineForFirestore);\n });\n});https://github.com/firebase/functions-samples/blob/c4fde45b65fab584715e786ce3264a6932d996ec/Node-1st-gen/presence-firestore/public/index.js#L68-L112\n```\n\nWith these changes we've now ensured that the *local* Cloud Firestore state will always\nreflect the online/offline status of the device. This means you can listen to the\n`/status/{uid}` document and use the data to change your UI to reflect connection\nstatus. \n\nWeb \n\n```javascript\nuserStatusFirestoreRef.onSnapshot(function(doc) {\n var isOnline = doc.data().state == 'online';\n // ... use isOnline\n});https://github.com/firebase/functions-samples/blob/c4fde45b65fab584715e786ce3264a6932d996ec/Node-1st-gen/presence-firestore/public/index.js#L118-L121\n```\n\nUpdating Cloud Firestore globally\n\nAlthough our application correctly reports online presence to itself, this status\nwill not be accurate in other Cloud Firestore apps yet because our \"offline\"\nstatus write is local only and won't be synced up when a connection is restored. To counter\nthis, we'll use a Cloud Function which watches the `status/{uid}` path in Realtime\nDatabase. When the Realtime Database value changes the value will sync to Cloud Firestore\nso that all users' statuses are correct. \n\nNode.js \n\n```javascript\nfirebase.firestore().collection('status')\n .where('state', '==', 'online')\n .onSnapshot(function(snapshot) {\n snapshot.docChanges().forEach(function(change) {\n if (change.type === 'added') {\n var msg = 'User ' + change.doc.id + ' is online.';\n console.log(msg);\n // ...\n }\n if (change.type === 'removed') {\n var msg = 'User ' + change.doc.id + ' is offline.';\n console.log(msg);\n // ...\n }\n });\n });https://github.com/firebase/functions-samples/blob/c4fde45b65fab584715e786ce3264a6932d996ec/Node-1st-gen/presence-firestore/public/index.js#L128-L147\n```\n\nOnce you deploy this function, you'll have a complete presence system running\nwith Cloud Firestore. Below is an example of monitoring for any users who\ncome online or go offline using a `where()` query. \n\nWeb \n\n```javascript\nfirebase.firestore().collection('status')\n .where('state', '==', 'online')\n .onSnapshot(function(snapshot) {\n snapshot.docChanges().forEach(function(change) {\n if (change.type === 'added') {\n var msg = 'User ' + change.doc.id + ' is online.';\n console.log(msg);\n // ...\n }\n if (change.type === 'removed') {\n var msg = 'User ' + change.doc.id + ' is offline.';\n console.log(msg);\n // ...\n }\n });\n });https://github.com/firebase/functions-samples/blob/c4fde45b65fab584715e786ce3264a6932d996ec/Node-1st-gen/presence-firestore/public/index.js#L128-L147\n```\n\nLimitations\n\nUsing Realtime Database to add presence to your Cloud Firestore app is\nscalable and effective but has some limitations:\n\n- **Debouncing** - when listening to realtime changes in Cloud Firestore, this solution is likely to trigger multiple changes. If these changes trigger more events than you want, manually debounce the Cloud Firestore events.\n- **Connectivity** - this implementation measures connectivity to Realtime Database, not to Cloud Firestore. If the connection status to each database is not the same, this solution might report an incorrect presence state.\n- **Android** - on Android, the Realtime Database disconnects from the backend after 60 seconds of inactivity. Inactivity means no open listeners or pending operations. To keep the connection open, we recommended you add a value event listener to a path besides `.info/connected`. For example you could do `FirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced()` at the start of each session. For more information, see [Detecting Connection State](https://firebase.google.com/docs/database/android/offline-capabilities#section-connection-state)."]]