1인 개발

Flutter + Firebase Realtime Database 심화 CRUD 완전 분석!

withmilk 2025. 3. 30. 17:21

안녕하세요 😀 지난 포스트에서는 Firebase Realtime Database에서 CRUD 하는 방법을 설명했어요. 이번 편에서는 CRUD 심화편이에요. Realtime Database를 사용할 때 Create, Read, Update, Delete 하는 방법이 여러가지인데, 그 방법들을 모두 설명하면서 언제, 어떻게 써야하는지와 장단점을 비교해보려고 해요.


Firebase Reference란? (CRUD 전에 꼭 알아야 할 개념!)

Firebase Realtime Database에서 데이터를 저장하거나 읽으려면 "어디에 접근할 건지" 알려줘야 해요.
그걸 알려주는 게 바로 Reference (레퍼런스)예요!

레퍼런스는 데이터의 "주소"예요

집에 가려면 주소가 필요하듯, 데이터에 가려면 레퍼런스(주소)가 필요해요!

예를 들어, 아래와 같은 데이터 구조가 있다고 해볼게요.

{
  "users": {
    "user1": {
      "name": "철수",
      "age": 9
    },
    "user2": {
      "name": "영희",
      "age": 10
    }
  }
}

 

여기서 users/user1 이 철수 데이터가 있는 주소이고, users/user2 가 영희 데이터가 있는 주소에요.

Flutter에서 RTDB를 사용할 때, 이 주소에 접근하려면 다음과 같이 사용하면 돼요.

DatabaseReference ref1 = FirebaseDatabase.instance.ref('users/user1'); // 철수 데이터 참조
DatabaseReference ref2 = FirebaseDatabase.instance.ref('users/user2'); // 영희 데이터 참조

 

  • ref('경로') 안에 주소를 넣으면 해당 위치에 접근할 수 있어요.
  • 그 열쇠로 CRUD 작업을 하는 거죠! (set, get, update, remove 등)

RTDB는 계단식 구조 (Tree 구조)

RTDB는 데이터를 나무(tree)처럼 계단식으로 저장해요.

users
 └── user1
      ├── name: "철수"
      └── age: 9
 └── user2
      ├── name: "영희"
      └── age: 10

 

  • users: 사용자들 전체
  • users/user1: 철수라는 사용자 하나
  • users/user1/name: 철수의 이름

이렇게 점점 안쪽으로 들어가는 구조로 데이터가 저장되어 있어요. 그래서 레퍼런스도 점점 더 세부적으로 접근할 수 있어요!

코드로 접근하는 예시를 보면 다음과 같아요.

// users 레퍼런스
var usersRef = FirebaseDatabase.instance.ref('users');

// users/user1 데이터에 접근
var user1Ref = usersRef.child('user1');

// users/user1/name 유저의 이름에 접근
var user2NameRef = user1Ref.userRef.child('name');
// 또는 다음처럼
var user2NameRef = FirebaseDatabase.instance.ref('users').child('user1').child('name');

 

  • 전체 사용자 불러오기 : ref('users').get()
  • 특정 유저(user1) 데이터만 불러오기 : ref('users/user1').get()
  • 특정 유저 유저 이름만 불러오기 : ref('users/user1/name').get()

이제 데이터의 위치를 정확히 알고 있으니, 이 주소를 이용해서 본격적으로 CRUD 작업(CREATE, READ, UPDATE, DELETE)을 할 준비가 된 거예요! 자, 그럼 이제 CRUD에 대해 본격적으로 들어가 볼까요?


1. Create

[방법1] set() - 특정 위치에 새로 저장하기

FirebaseDatabase.instance.ref('users/user1').set({
  'name': '철수',
  'age': 9,
});
  • ✅ 장점 : 아주 직관적으로 users/user1에 철수라는 데이터를 강제로 덮어쓰는 형태로 저장할 수 있어요.
  • ❌ 단점 : user1이라는 주소에 있던 기존 데이터가 덮어씌워지기 때문에 조심해야 해요.
  • 활용 : 이미 정해진 데이터를 사용하거나, 유저가 입력한 데이터를 그대로 사용해서 데이터를 저장할 때 자주 사용해요.
    1. 닉네임 중복 체크를 위해서 닉네임만 저장하는 레퍼런스를 만든 뒤, nicknames/철수 에 데이터를 저장해두는 거에요.
    2. 유저가 새로 가입했을 때, Firebase auth에서 받은 uuid를 사용해서 유저 정보를 저장해요.

 

[방법2] push().set() - 고유 키로 저장 (중복 없이 여러 개 저장)

FirebaseDatabase.instance.ref('users').push().set({
  'name': '영희',
  'age': 10,
});

push()라는 함수를 부르면, users 밑에 중복되지 않는 고유 주소를 하나 생성해줘요. 'user1' 이라는 주소 대신 랜덤하고 고유한 키를 가지는 주소가 만들어지게 되고, 그 위치에 영희라는 데이터를 저장하는 방식이에요.

 

  • ✅ 장점 : 자동으로 ID 만들어줌 → 채팅, 댓글 등에 좋아요
  • ❌ 단점 : 저장된 키값이 랜덤이라 불러올 때 관리 필요.
  • 활용 : 많은 경우에 고유 키를 사용해요. 데이터를 새로 써놓는 것에 의미가 크고, 키 값은 중요하지 않을 때에요.
    1. 유저가 로그인을 안하고 게스트 로그인을 했을때 게스트 유저의 정보를 저장할 때 사용해요.
    2. 유저의 데이터를 로깅할 때에는 키 값 자체에는 의미가 없으니, 로깅 데이터를 저장할 때 사용해요.
    3. 유저가 친 채팅 메세지를 저장할 때 사용해요.
    4. 유저가 새로 그룹을 생성했을 때, 랜덤 키로 그룹 정보를 저장해요.

 

💡알아두면 좋은 팁 : 한 레퍼런스 내에서 push로 생성되는 고유한 키는 완전 랜덤은 아니고 시간에 따라 오름차순으로 키 값이 만들어져요. 예를 들어, 채팅 메세지를 push를 통해서 저장한다면 무조건 나중에 보낸 메세지가 뒤쪽에 오도록 정렬되어 있어요!!

 

방법1, 2를 통해서 데이터를 실제로 저장해보면, 다음과 같이 철수는 'user1'이라는 키 값으로, 영희는 '-OM0pXcb-sptpNF1Womf' 라는 키 값으로 데이터가 저장된 것을 확인할 수 있어요.

Create 예시


2. READ

[방법1] get() – 한 번만 데이터 불러오기

DataSnapshot snapshot = await FirebaseDatabase.instance.ref('users/user1').get();
print(snapshot.value);

 

  • ✅ 장점 : 필요할 때 한 번만 불러옴 → 성능 좋음
  •  단점 : 실시간 업데이트 안됨
  • 활용 : 딱 한 번 데이터를 불러올 때 사용해요.

 

[방법2] onValue – 실시간으로 계속 듣기

FirebaseDatabase.instance.ref('users/user1').onValue.listen((event) {
  print(event.snapshot.value);
});

 

 

  • 장점 : 데이터 바뀌는 즉시 알 수 있음
  • 단점 : 지속적으로 리소스 사용 → 너무 많이 쓰면 느려짐
  • 활용 : 데이터를 실시간으로 사용해서 화면을 그려줄 때 사용해요.
    1. 채팅 화면에서는 새로운 메세지가 올때마다 화면을 새로 그려줘야하기 때문에 listen으로 듣고 있어야 해요.
    2. 이벤트 페이지에서 실시간으로 참여한 유저수를 보여주고 싶을때 listen으로 듣고 있어야 해요.
    3. 수강신청 페이지에서 이미 수강 인원이 꽉 찬 경우 신청하지 못하게 UI를 비활성화하기 위해서 수강 인원을 듣고 있어야 해요.

 

[방법3] once() – 한 번만 실시간으로 받기 (old API)

  • get()으로 대체되는 중이라 이제는 거의 사용 안 해요
  • 활용 : 사용하지 않아요.

3. Update

[방법1] set() – 전체 덮어쓰기

// 원래 있던 철수 데이터가 영희 데이터로 덮어씌워짐. 덮어 씌워지기 때문에 age도 사라진다.
FirebaseDatabase.instance.ref('users/user1').set({
  'name': '영희',
});

 

  • ❌ 단점 : 기존에 있던 다른 데이터 다 날아갈 수 있어요
  • 활용 : 수정을 할 때 무조건 데이터를 초기화 해야할 때 사용해요. 전체 데이터보다는 딱 1개의 레코드를 수정할 때 사용할 수 있어요.
    1. 유저가 본인의 닉네임을 변경했을 때 ref(users/user1/name).set("영희") 처럼 사용해요.

 

[방법2] update() – 일부만 변경

FirebaseDatabase.instance.ref('users/user1').update({
  'age': 11,
});
  • ✅ 장점 : 원하는 값만 수정 가능 → 안전하고 편리
  • 활용 : 거의 모든 경우에 update를 사용해서 데이터를 수정해요. 데이터를 여러 곳에 많이 써놓는 RTDB의 특성때문에, 여러 레퍼런스에 있는 데이터를 한 번에 수정할 때 사용할 수 있어요.
    1.  거의 모든 데이터 수정에서 사용해요.

 

보통 아래처럼 많이 사용합니다!

FirebaseDatabase.instance.ref().update({
  'users/user1/age': 11,
  'groups/group1/member/user1/age': 11,
});

update를 사용해서 유저가 자기의 나이를 변경했을 때, users의 내 정보를 변경하면서 groups/group1에 저장되어 있는 내 나이 정보도 한 번에 변경할 수 있어요.


4. Delete

[방법1] remove() – 해당 경로 완전히 삭제

FirebaseDatabase.instance.ref('users/user1').remove();

 

  • 장점 : 완전히 삭제됨
  • 단점 : 복구 불가
  • 활용 : 해당 레퍼런스를 깔끔하게 삭제하고 싶을 때 사용할 수 있어요. 하지만 [방법2]의 update로 삭제하는 것이 훨씬 편하기 때문에 잘 사용하지 않아요.
    1. 유저가 탈퇴해서 데이터를 삭제할 때
    2. 그룹을 삭제해서 그룹 정보를 삭제할 때

 

[방법2] update(null) – 특정 필드만 삭제

// [방법1]과 동일한 결과
FirebaseDatabase.instance.ref('users/user1').update(null);

// 유저의 나이만 지우고 싶을 때 사용. "철수"라는 이름은 남아 있음.
FirebaseDatabase.instance.ref('users/user1').update({
  'age': null,
});

 

  •  장점 : 일부 데이터만 지우고 나머지는 유지 가능
  • 활용 : 대부분의 데이터 삭제도 update를 사용해요. 여러 곳에 있는 데이터를 한 번에 지울 수 있기 때문이에요.
    1. 대부분의 삭제에서 사용해요.
    2. 여러 데이터를 한 번에 지워야하는 경우에 사용해요.

 

// 유저 목록의 정보와, 가입한 그룹, 이벤트에서 유저의 정보를 한 번에 삭제하는 코드
FirebaseDatabase.instance.ref().update({
  'users/user1': null,
  'groups/group1/member/user1': null,
  'event/participants/user1': null
});

이 예시처럼 유저가 탈퇴했을 때, [방법1]을 사용하면 각각의 주소에 remove를 실행해줘야 하지만, update를 사용하면 한번의 호출로 삭제하고 싶은 데이터를 모두 한 번에 싹 지울 수 있어요.


마무리하며

지금까지 Flutter와 Firebase Realtime Database를 이용한 CRUD 작업을 심화적으로 알아봤어요. 각각의 메서드가 언제, 왜 사용되는지를 이해하면 단순히 코드를 외우는 게 아니라 스스로 판단하고 선택하는 능력이 생겨요. 이런 기초적인 부분이 튼튼해야 나중에 앱을 복잡하게 만들 때도 당황하지 않아요. 하나하나 천천히 실습하면서 직접 손으로 해보면 금방 익숙해질 거예요 😊

 

딱 한마디로 정리하자면 RTDB를 사용하고 구현할 때의 핵심은

onValue로 데이터를 실시간으로 받으면서 유저의 행동에 따라 push와 update 함수를 어떻게 잘 활용하지 고민하는 것

이에요

 

이제 여러분은 Firebase Realtime Database를 사용하면서 데이터를 만들고(Create), 읽고(Read), 수정하고(Update), 삭제(Delete)하는 핵심 기술을 충분히 익힌 셈이에요! 다음 단계에서는 이 CRUD 작업들을 UI 버튼과 연결해보고, 리스트 뷰에 실시간 데이터 바인딩도 해보면서 더 흥미로운 기능을 구현해볼 수 있어요.