오늘은 Firebase에서 collection 안에 정보를 직접 저장하는 것이 아닌 id를 통해 가져오는 방법으로 데이터 구조를 변경해보려고 합니다.
변경전
data class PostDataModel( val uid: String, ─┐ val profileImage: String, │ val name: String, │ → user data val email: String, │ val postId: String, ─┘ val imageList = imageList, ─┐ val postText: String, │ val mapData = MapDataModel(), │ → post data val createdAt: String ─┘ )
- 원래는 다음과 같이 포스트에 대한 data class 안에 고유 아이디 값, 이름, 이메일, 프로필 사진 등 유저의 정보를 직접 참조 할 수 있도록 데이터 구조를 구성했었는데, post data를 가져올 때 user라는 collection을 참조하여 uid 값에 맞는 user 정보를 가져오는 것으로 데이터 구조를 변경해 보려고 합니다. 그렇게 되면 post data 안에는 고유 아이디 값인 uid만 넣어주면 되는 것이므로 한층 간결해 질 것으로 예상됩니다.
↓
↓
↓변경후
data class PostDataModel( val uid: String, val postId: String, val imageList = imageList, val postText: String, val mapData = MapDataModel(), val createdAt: String ) data class UserDataModel( val uid: String, val name: String, val email: String, val profileImage: String?, val createdAt: String, val intro: String? ) // join two collections data class PostModel( val userData: UserDataModel, val postData: PostDataModel )
- user data와 post data를 분리하여 주고 post data를 작성한 유저의 uid만 post data 안에 넣어줍니다. 게시글을 작성하는건 현재 유저만 가능한 일이므로 current user의 uid가 들어가면 되겠습니다. 여기서 기존과 다른 점은 data class를 하나 더 생성하여 post data와 user data를 같이 받아올 수 있는 data class를 하나 만들어줘야 합니다. 예시에서 PostModel이
그 data class 입니다. 이제 repository에서 로직을 작성해 보겠습니다.
현재 작성중인 프로젝트의 repositoryImpl의 구문을 paging 작업 빼고 가져왔습니다.
db.collection("post") .orderBy("createdAt", Query.Direction.DESCENDING) .get() .addOnSuccessListener { postData -> val documents = postData.documents val postResponse = postData.toObjects(PostDataResponse::class.java) postResponse.map { postEntity -> db.collection("user").document(postEntity.uid).get() .addOnSuccessListener { userData -> val userEntity = userData.toObject(UserDataResponse::class.java)?.toEntity() if (userEntity != null) { postList.addAll(listOf(PostEntity(userEntity, postEntity))) } postDocuments.addAll(documents) trySend(postList) } } }
1. post data 가져오기 db.collection("post").orderBy("createdAt", Query.Direction.DESCENDING).get() - 먼저 fireStore database의 post collection에서 정보를 가져옵니다.
2. 가져온 post data를 data class로 변환시켜주기 .addOnSuccessListener { postData -> val documents = postData.documents val postResponse = postData.toObjects(PostDataResponse::class.java) - addOnSuccessListener는 firebase에서 지원해주는 로직으로 데이터를 받아오는 것이 성공했을 때를 의미합니다. - 받아온 data의 documents를 data class로 변환(toObjects) 해줍니다.
3. user data 가져오기 postResponse.map { postEntity -> db.collection("user").document(postEntity.uid).get() - toObjects 시켜준 데이터에서 각 data 마다의 uid를 가져와서 uid에 맞는 user data를 가져와 줍니다. - 네이밍이 조금 이상하게 되어있긴합니다...ㅠㅠ
4. list 전달하기 .addOnSuccessListener { userData -> val userEntity = userData.toObject(UserDataResponse::class.java)?.toEntity() if (userEntity != null) { postList.addAll(listOf(PostEntity(userEntity, postEntity))) } postDocuments.addAll(documents) trySend(postList) } } - 가져온 user data도 data class로 toObject 해주고 postList를 만들어서 안에 addAll 해주었습니다. - 이때 list에 들어가야 하는 data는 아까 전에 만들어둔 PostModel 입니다! ↓ data class PostModel( val userData: UserDataModel, val postData: PostDataModel )
- 좀 뒤죽박죽 작성한 것 같긴한데 핵심은 이렇습니다.
- user data와 post data를 분리한다.
- post data를 가져올 때 각 post data의 uid를 참조하여 uid 값에 맞는 user data를 가져온다.
- 두가지 데이터를 참조하는 data class를 만들어 list로 받아준다.
이렇게 하여 data를 받아주면 collection을 따로 관리할 수 있어서 더 편리하기도 하고 나중에 프로젝트의 규모가 커질수록 더 효율적일 것 같습니다! 규모가 커진다는 것은 그만큼 관리해야 하는 데이터가 늘어난다는 것인데 그때도 모든 유저의 데이터를 각 댓글, 게시글, 대댓글 마다 넣어준다면 쓸모없는 데이터를 계속하여 넣어주는 느낌이지 않을까 싶습니다.
처음 data 구조를 구성할 때도 이게 맞나 긴가민가 했지만 좋은 선생님 덕분에 방법을 알아간 것 같아서 좋습니다!
더 깊게 공부하고 data 구조를 공부하려면 mongoDB, SQL Join 등 키워드로 검색 해봐야 겠습니다!
.
.
.