0Pricing
Android Academy · 강의

Cloud Firestore 기초

실시간 데이터를 읽고 씁니다.

Cloud Firestore 기초은(는) CoddyKit의 무료 Android Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Android Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Android Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

Cloud Firestore란 무엇인가요?

Cloud Firestore는 유연하고 확장 가능한 Firebase의 NoSQL 데이터베이스입니다. 데이터는 문서로 저장되며, 문서는 컬렉션으로 그룹화됩니다.

  • 문서는 키/값 필드의 집합입니다(JSON 객체와 비슷합니다).
  • 컬렉션은 문서를 담는 컨테이너입니다.
  • 문서에는 하위 컬렉션이 포함될 수 있어 트리 구조를 만들 수 있습니다.

Firestore는 실시간 업데이트도 제공하며 기본적으로 오프라인에서도 작동합니다.

Firestore 인스턴스 가져오기

Firebase.firestore를 통해 데이터베이스에 접근합니다. 여기에서 collection("name")으로 컬렉션에 접근하고, document("id")로 특정 문서에 접근합니다.

참조는 만들 때 비용이 거의 들지 않습니다. 참조는 데이터 자체가 아니라 데이터의 위치를 설명하기 때문입니다.

import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore

val db = Firebase.firestore

val usersRef = db.collection("users")
val oneUser = db.collection("users").document("abc123")

데이터 모델링하기

Firestore는 Kotlin 데이터 클래스에 자연스럽게 매핑됩니다. 각 속성은 문서의 필드가 됩니다.

Firestore가 문서를 다시 객체로 역직렬화할 수 있도록 인수가 없는 생성자를 제공합니다(기본값으로 처리할 수 있습니다).

data class Note(
    val title: String = "",
    val body: String = "",
    val done: Boolean = false,
    val createdAt: Long = 0L
)

문서 쓰기

set을 사용해 문서를 만들거나 덮어씁니다. add를 사용하면 Firestore가 ID를 생성하고, document(id).set(...)을 사용하면 직접 ID를 지정할 수 있습니다.

이 호출들은 Task를 반환하며, 코루틴에서는 await()로 기다릴 수 있습니다.

import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await

suspend fun addNote(note: Note): String {
    val ref = Firebase.firestore
        .collection("notes")
        .add(note)          // auto-generated ID
        .await()
    return ref.id
}

문서 읽기

get()은 문서를 한 번 가져옵니다. toObject(Note::class.java)를 사용해 데이터 클래스로 변환합니다.

항상 exists()를 확인해야 합니다. 존재하지 않는 문서를 참조하면 실제 문서가 존재하지 않는 스냅샷이 반환됩니다.

import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await

suspend fun loadNote(id: String): Note? {
    val snapshot = Firebase.firestore
        .collection("notes")
        .document(id)
        .get()
        .await()
    return if (snapshot.exists()) snapshot.toObject(Note::class.java) else null
}

업데이트 및 삭제하기

update는 문서의 나머지 내용은 건드리지 않고 특정 필드만 변경합니다. delete는 문서를 완전히 삭제합니다.

문서가 없을 때 문서를 만들면서 일부 필드만 쓰려면 set(..., SetOptions.merge())를 사용합니다.

import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await

suspend fun markDone(id: String) {
    Firebase.firestore.collection("notes").document(id)
        .update("done", true)
        .await()
}

suspend fun removeNote(id: String) {
    Firebase.firestore.collection("notes").document(id)
        .delete()
        .await()
}

컬렉션 쿼리하기

whereEqualTo, whereGreaterThan, orderBy, limit 등을 연결해 필터를 적용하면서 쿼리를 구성합니다.

쿼리는 QuerySnapshot을 반환합니다. 문서를 순회하며 각각을 모델 객체로 변환합니다.

import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await

suspend fun pendingNotes(): List<Note> {
    val snap = Firebase.firestore.collection("notes")
        .whereEqualTo("done", false)
        .orderBy("createdAt")
        .limit(20)
        .get()
        .await()
    return snap.documents.mapNotNull { it.toObject(Note::class.java) }
}

실시간 리스너

Firestore의 가장 강력한 기능은 실시간 처리입니다. addSnapshotListener는 현재 데이터를 즉시 전달한 다음, 변경 사항이 생길 때마다 자동으로 전달합니다.

이 함수는 ListenerRegistration을 반환합니다. 더 이상 업데이트를 받을 필요가 없으면 remove()를 호출합니다.

import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore

val registration = Firebase.firestore.collection("notes")
    .whereEqualTo("done", false)
    .addSnapshotListener { snapshot, error ->
        if (error != null || snapshot == null) return@addSnapshotListener
        val notes = snapshot.toObjects(Note::class.java)
        println("Now have ${notes.size} pending notes")
    }

// Later: registration.remove()

Flow로 실시간 데이터 다루기

Compose에서는 Firestore를 Kotlin Flow로 노출하는 방식이 일반적입니다. callbackFlow는 리스너 콜백을 flow로 연결하고, awaitClose는 수집이 중단될 때 리스너를 제거합니다.

import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow

fun notesFlow(): Flow<List<Note>> = callbackFlow {
    val reg = Firebase.firestore.collection("notes")
        .addSnapshotListener { snap, err ->
            if (err == null && snap != null) {
                trySend(snap.toObjects(Note::class.java))
            }
        }
    awaitClose { reg.remove() }
}

Compose에 데이터 표시하기

collectAsStateWithLifecycle()로 flow를 수집하고 LazyColumn에 렌더링합니다. Firestore의 데이터가 변경될 때마다 목록이 자동으로 업데이트되므로 수동 새로 고침이 필요하지 않습니다.

@Composable
fun NotesScreen(viewModel: NotesViewModel) {
    val notes by viewModel.notes.collectAsStateWithLifecycle()

    LazyColumn {
        items(notes) { note ->
            ListItem(
                headlineContent = { Text(note.title) },
                supportingContent = { Text(note.body) }
            )
        }
    }
}

보안 규칙이 중요한 이유

Firestore는 기본적으로 잠겨 있습니다. 보안 규칙이 각 경로를 읽거나 쓸 수 있는 사용자를 결정합니다. 보안 규칙은 서버에서 실행되므로 클라이언트가 우회할 수 없습니다.

일반적인 규칙은 사용자가 인증된 uid를 키로 사용해 자신의 데이터에만 접근하도록 허용하는 것입니다.

// firestore.rules
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId}/{document=**} {
      allow read, write: if request.auth != null
                         && request.auth.uid == userId;
    }
  }
}

빠른 확인

기반이 되는 Firestore 데이터가 변경될 때마다 수동으로 새로 고치지 않아도 즉시 업데이트되는 Compose 목록을 만들려고 합니다. 어떤 API를 사용해야 할까요?

복습: Firestore

이제 Cloud Firestore로 데이터를 저장하고 동기화할 수 있습니다.

  • 데이터는 컬렉션 안의 문서로 저장하며 Kotlin 데이터 클래스로 모델링합니다.
  • add/set으로 쓰고, get으로 읽으며, update/delete로 변경합니다.
  • whereEqualTo, orderBy, limit으로 쿼리합니다.
  • 실시간 UI에는 addSnapshotListener(또는 callbackFlow)를 사용합니다.
  • request.auth.uid를 기준으로 하는 보안 규칙으로 데이터를 보호합니다.

다음 주제: 앱이 닫혀 있을 때도 Cloud Messaging으로 사용자에게 도달하기

자주 묻는 질문

“Cloud Firestore 기초” 강의는 무료인가요?

네 — “Cloud Firestore 기초” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Android Academy 강의 전체를 잠금 해제할 수 있습니다. Android Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“Cloud Firestore 기초”에서 뭘 배우나요?

실시간 데이터를 읽고 씁니다. 브라우저에서 직접 실행하는 실습 코드로 Android Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Android Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Android Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“Cloud Firestore 기초” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Android Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Android Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. Firebase 설정
  2. Firebase 인증
  3. Cloud Firestore 기초
  4. Cloud Messaging으로 푸시 알림 보내기
← Android Academy(으)로 돌아가기