두 솔루션 모두 다음 기능을 제공한다.
주요 고려사항에 따라 내가 선택해야할 DB가 결정된다.
아래 링크는 Firebase 공식 홈페이지에서 제공하는 고려사항이다. 읽고 결정한다.
데이터베이스 선택: Cloud Firestore 또는 실시간 데이터베이스 | Firebase Documentation
push()
를 사용하여 자동으로 지정할 수도 있다.💡 키를 직접 만드는 경우 키는 UTF-8로 인코딩되어야 하고 768바이트 이하여야 하며
.
,$
,#
,[
,]
,/
, ASCII 제어문자 0~31 또는 127을 포함할 수 없다. 값 자체에도 ASCII 제어 문자를 사용할 수 없다.
데이터 중첩 배제
Firebase Real-Time Database는 최대 32단계의 데이터 중첩을 허용하지만, 실제 구현에서는 데이터 구조를 최대한 평면화하는 것이 좋다.
중첩을 한다면, 데이터베이스의 특정 위치에서 데이터를 가져오면 모든 하위 노드가 함께 검색되고, 사용자에게 데이터베이스의 특정 노드에 대한 읽기 또는 쓰기 권한을 부여하면 해당 노드에 속한 모든 데이터에 대한 권한이 함께 부여된다.
데이터를 중첩한 예시 (이렇게 하면 안된다!)
{
// This is a poorly nested data architecture, because iterating the children
// of the "chats" node to get a list of conversation titles requires
// potentially downloading hundreds of megabytes of messages
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"messages": {
"m1": { "sender": "ghopper", "message": "Relay malfunction found. Cause: moth." },
"m2": { ... },
// a very long list of messages
}
},
"two": { ... }
}
}
{
// Chats contains only meta info about each conversation
// stored under the chats's unique ID
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
"timestamp": 1459361875666
},
"two": { ... },
"three": { ... }
},
// Conversation members are easily accessible
// and stored by chat conversation ID
"members": {
// we'll talk about indices like this below
"one": {
"ghopper": true,
"alovelace": true,
"eclarke": true
},
"two": { ... },
"three": { ... }
},
// Messages are separate from data we may want to iterate quickly
// but still easily paginated and queried, and organized by chat
// conversation ID
"messages": {
"one": {
"m1": {
"name": "eclarke",
"message": "The relay seems to be malfunctioning.",
"timestamp": 1459361875337
},
"m2": { ... },
"m3": { ... }
},
"two": { ... },
"three": { ... }
}
}
그룹 색인
지정// An index to track Ada's memberships
{
"users": {
"alovelace": {
"name": "Ada Lovelace",
// Index Ada's groups in her profile
"groups": {
// the value here doesn't matter, just that the key exists
"techpioneers": true,
"womentechmakers": true
}
},
...
},
"groups": {
"techpioneers": {
"name": "Historical Tech Pioneers",
"members": {
"alovelace": true,
"ghopper": true,
"eclarke": true
}
},
...
}
}
싱가포르
선택 후 다음 (이유는 우리나라랑 위치상 가깝기 때문, 순전히 내 생각)잠금모드
선택 후 설정+추가 적용 사항
app/build.gradle(Module:..)의 dependencies에 firebase-database 추가 후 Sync now...
kotlin 이라 ktx가 붙음
dependencies {
...
implementation 'com.google.firebase:firebase-database-ktx:20.0.4'
}
DB 선언 후 접속 테스트
Database Region이 US가 아닐 경우 database의 url을 추가적으로 넣어줘야함(이유는 이 페이지의 error에서 참고)
class RegistrationActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Region이 US일 경우
val database = Firebase.database
val myRef = database.getReference("message")
myRef.setValue("Hello, World!")
// Region이 US가 아닐 경우 (ex: 벨기에, 싱가포르)
val database = Firebase.database("https://worldchat-chris-4342-default-rtdb.asia-southeast1.firebasedatabase.app")
val myRef = database.getReference("message")
myRef.setValue("Hello, World!")
}
}
결과
+DB 추가 명령어
Firebase Authentication의 userId를 받아서 내용 저장
private val database: DatabaseReference =
Firebase.database("https://worldchat-chris-4342-default-rtdb.asia-southeast1.firebasedatabase.app").reference
// user 라는 경로에 변수 userId에 해당하는 값(user라는 데이터 클래스의 값)을 넣는다
fun addUser(userId: String, user: User) {
database.child("users").child(userId).setValue(user)
}
+결과
email, uid는 setValue(user) 내용
Error message
Firebase Database connection was forcefully killed by the server. Will not attempt reconnect. Reason: Database lives in a different region. Please change your database URL to https://worldchat-chris-4342-default-rtdb.asia-southeast1.firebasedatabase.app
2022-04-28 14:32:21.520 8589-8623/com.crystal.worldchat V/FA: Inactivity, disconnecting from the service
조언 적용 전 / 후
Firebase 데이터는 FirebaseDatabase 참조에 기록되고, 참조에 비동기 리스너를 연결하여 검색할 수 있다. 리스너는 데이터의 초기 상태가 확인될 때 한번 트리거 된 후 데이터가 변경될 때마다 다시 트리거된다.
DatabaseReference 가져오기
DatabaseReference
의 인스턴스가 필요하다. private lateinit var database: DatabaseReference
// ...
database = Firebase.database.reference
Data 쓰기
1. 기본 쓰기 작업 : setValue() 코드를 사용하여 지정된 참조에 데이터를 저장하고 해당 경로의 기존 데이터를 모두 바꿈
@IgnoreExtraProperties
data class User(val username: String? = null, val email: String? = null) {
// Null default values create a no-argument default constructor, which is needed
// for deserialization from a DataSnapshot.
}
fun writeNewUser(userId: String, name: String, email: String) {
val user = User(name, email)database.child("users").child(userId).setValue(user )
}
database.child("users").child(userId).child("username").setValue(name)