안녕하세요 😀
Firebase Realtime Database(Firebase RTDB)를 사용할 때, 코딩보다 더 중요한 게 바로 데이터 구조 설계예요.
앱을 만들다 보면 데이터를 어떻게 저장하고 불러올지 고민하게 되는데, 처음부터 구조를 잘 설계하지 않으면, 나중에 복잡해지고 느려지고… 아주 큰 후회를 하게 됩니다 😢 이번 글에서는 Firebase RTDB를 쓸 때 데이터를 어떻게 설계하면 좋은지, 초보자도 이해할 수 있도록 친절하게 알려드릴게요!
Firebase RTDB를 사용하려고 docs 페이지에 들어가보면, 데이터베이스 구조화를 잘 해야한다고 설명하고 있는 것을 확인할 수 있어요. 저도 처음에 이 페이즈를 보았을 때 어떻게 해야하는지에 대해서 정확하게 잘 모르고 진행했었어요. 제가 RTDB를 사용해서 개발하면서 이해한 것들에 대해서 풀어서 설명해보려고 해요.
📦 RTDB는 "트리(Tree)" 구조예요
RTDB는 JSON 형태로 데이터를 저장하는데, 이건 마치 나무처럼 뻗어 있는 구조예요.
{
"users": {
"user1": {
"name": "철수",
"age": 9
},
"user2": {
"name": "영희",
"age": 10
}
}
}
위처럼 계단식으로 내려가는 구조예요. 그래서 잘못 설계하면 데이터가 너무 깊어져서
한 번에 많은 걸 불러오게 되고, 속도도 느려지고, 관리도 어려워져요!
CRUD에서 READ를 한다고 했을 때, users가 너무 크면 그만큼 데이터를 한 번에 큰 데이터를 읽게되고 그만큼 DB 사용량이 기하급수적으로 늘어나게 돼요.
좋은 데이터 설계의 기본 원칙
1️⃣ 정규화(Normalization)처럼 설계하기
- 하나의 정보는 하나의 위치에만 저장하기
- 중복 데이터 금지
2️⃣ 데이터는 평평하게(Flat하게)
- 너무 깊은 중첩은 피하기
- 필요한 키는 직접 만들어서 관리하기
3️⃣ ID 기반으로 접근하기
- 유저 ID, 게시글 ID 등을 키로 사용하면 검색과 접근이 쉬워져요.
1. 나쁜 예 vs 좋은 예 비교
❌ 나쁜 설계 예시 (중첩이 너무 깊어요.)
{
"users": {
"user1": {
"name": "철수",
"age": 9,
"posts": {
"post1": {
"title": "첫 글",
"content": "안녕하세요"
},
"post2": {
"title": "두번째 글",
"content": "안녕히계세요"
}
}
},
"user2": {
"name": "영희",
"age": 10,
}
}
}
- 유저의 정보만 읽어오고 싶을 때에도, 유저가 작성한 포스트도 모두 한 번에 읽어야 해요. 유저가 작성한 포스트가 많다면 받아야 하는 데이터가 엄청 커질 거에요. RTDB에서는 데이터를 다운로드한 만큼 과금되기 때문에 최대한 줄여야해요.
- 모든 포스트를 불러와서 포스트 목록을 보여주기 위해서는 모든 유저를 돌아야 해요. 매우 이상한 일이에요.
- 유저 안에 포스트가 있기 때문에 유저 탈퇴 시 글도 같이 지워질 수 있어요.
✅ 좋은 설계 예시 (관계를 분리하고 ID로 연결)
{
"users": {
"user1": {
"name": "철수",
"age": 9
},
"user2": {
"name": "영희",
"age": 10
}
},
"posts": {
"post1": {
"userId": "user1",
"title": "첫 글",
"content": "안녕하세요"
},
"post2": {
"userId": "user1",
"title": "두번째 글",
"content": "안녕히계세요"
}
}
}
- 글 목록을 쉽게 불러올 수 있어요.
- 유저 정보랑 글 정보를 따로 관리할 수 있어요. 유저의 회원 정보를 보여주고 싶을 때는 유저 정보만 읽을 수 있고, 글 정보를 보여주고 싶을 때는 글 정보만 읽으면 되기 때문에 데이터 다운로드 크기를 최적으로 사용할 수 있어요.
- 확장성이 좋아요!
위처럼 설계했을 때 실제 Firebase 콘솔에서는 아래처럼 보여요.
확장성에 대한 예시
"posts": {
"postId456": {
"userId": "userId123",
"title": "제목",
"content": "내용",
"createdAt": 1710000000000
}
},
"comments": {
"commentId789": {
"postId": "postId456",
"userId": "userId123",
"text": "좋아요!",
"createdAt": 1710000000000
}
}
각각의 글에 대한 댓글 데이터를 추가하고 싶을 때에는 새로 comments 라는 레퍼런스를 사용하면 돼요. 그리고 댓글을 단 글의 postId와 userId를 comment 데이터에 저장하면 되니까요.
- postId와 userId를 같이 저장 → 관계 파악이 쉬워요
- createdAt(작성 시간)은 정렬할 때 유용해요
ID를 키로 설정해서 검색이 쉽게 하자!!
오늘의 첫번째 핵심이에요. RTDB를 사용할 때에는 검색하고 싶은 ID를 키로 사용하는 것이 최고의 방법이에요. 예를 들면 아래와 같아요.
{
"users": {
"user1": {
"name": "철수"
},
"user2": {
"name": "영희"
}
},
"groups": {
"group1": {
"name": "최고의 그룹",
"members": {
"user1": true,
"user2": true
}
},
"group2": {
"name": "철수만 가입하는 그룹",
"members": {
"user1": true
}
}
}
"user_group_map": {
"user1": ["group1", "group2"],
"user2": ["group1"]
}
}
user1과 user2라는 유저가 있고 2개의 그룹이 있어요. user1은 group1, group2에 모두 가입했고 user2는 group1에만 가입했어요.
- 1️⃣ group 밑에 members라는 레퍼런스가 있을 때 members의 키를 user id로 사용했기 때문에 각각의 그룹에 누가 가입했는지 쉽게 알 수 있어요. 내가 그룹1에 가입했는지 알고 싶다면, ref('groups/group1/members/user2').get()을 호출해서 데이터가 있는지 확인하면 빠르게 확인할 수 있죠.
- 2️⃣ user_group_map이라는 데이터를 읽었을 때에 각각의 유저가 몇개의 그룹에 가입했는지 빠르게 알 수 있어요. 내가 몇개의 그룹에 가입했는지 알고 싶다면, ref('user_group_map/user2').get() 으로 빠르게 확인해볼 수 있죠.
데이터를 여러번 저장하는 것으로 내가 만드는 앱에서 필요한 데이터를 빠르게빠르게 읽어올 수 있어요.
중복 저장? 해도 돼요!
Firebase RTDB를 사용할 때에 또한 핵심적으로 생각해야하는 것은 중복 데이터 금지 를 크게 신경 쓰지 않고 DB를 설계해야 하는 거에요.
Firebase Realtime Database는 SQL이 아니기 때문에, 검색이 느린 대신 읽기는 빠르다는 특징이 있어요. SQL이 아니기 때문에 데이터를 필터링하고, 정렬하거나 간단한 연산을 할 수가 없어요.
그래서 가끔은 groups, user_group_map의 예시처럼 데이터를 중복해서 저장해도 괜찮아요!
"postLikes": {
"postId456": {
"userId123": true,
"userId456": true
}
},
"postLikeCount": {
"postId456": 2
}
이처럼, 누가 눌렀는지도 저장하고 숫자도 별도로 저장해서 목록에서 빠르게 보여줄 수 있어요
마무리하며..
Firebase RTDB를 사용하기 위해 데이터를 설계할 때 다음 체크리스트를 활용하면서 해보세요.
- ✅ 데이터는 평평하게
- ✅ 너무 깊은 구조 ❌
- ✅ 관계는 ID로 연결
- ✅ 중복 저장은 읽기 성능을 위해 허용
- ✅ 시간 정보(createdAt) 활용
- ✅ 읽기 패턴을 먼저 생각하기 (어디서 자주 쓰는지)
처음에는 어떤 구조로 데이터를 저장해야 할지 막막하고 어려울 수 있어요. 하지만 걱정하지 마세요. 누구나 처음은 다 그렇고, 중요한 건 ‘지금’ 이 글을 보며 배우고 있다는 것 자체가 성장의 증거예요. 데이터를 깔끔하고 효율적으로 설계하는 습관은 단순히 앱을 잘 만드는 걸 넘어, 당신이 진짜 개발자로 나아가는 첫걸음이 될 거예요.
앞으로 앱에 다양한 기능을 추가하면서 더 복잡한 데이터 구조를 마주하게 될 거예요. 그럴 때마다 오늘 배운 원칙들을 떠올려보세요. "데이터는 평평하게", "ID로 연결", "중복 저장은 OK!" 이런 기준을 바탕으로 천천히 구조를 만들어 나가면, 어떤 앱이든 자신 있게 도전할 수 있을 거예요. 그리고 나중에 추가될 기능들을 생각하면서 미리 고민해서 어떻게 새로운 관계를 지을지, 어떤 것들을 인덱싱해서 중복 저장할지에 대해서 생각하고 설계해두면 더 좋을거에요. 아직 배울 게 많지만, 너무 조급해하지 않아도 괜찮아요. 저와 함께 하나씩 차근차근 익혀가면 어느새 멋진 앱을 스스로 만들고 있는 자신을 발견하게 될 거예요.
'1인 개발' 카테고리의 다른 글
왜 1인 개발자는 Flutter로 시작해야 할까? (0) | 2025.04.06 |
---|---|
노코드 / 로우코드 vs Flutter + Firebase: 1인 개발자를 위한 현실적인 선택 (0) | 2025.04.06 |
Flutter + Firebase Realtime Database 심화 CRUD 완전 분석! (0) | 2025.03.30 |
Flutter에서 Firebase Realtime Database로 CRUD 하기! (1) | 2025.03.23 |
Firebase 프로젝트 만들고 Flutter 앱에 등록하기 (기초부터 찬찬히 알려드려요) (0) | 2025.03.23 |