Firestore 간단한 설명 및 사용

ChoiUS·2022년 11월 16일
0

Android

목록 보기
2/4

Firestore란?

NoSQL(비관계형) 데이터 베이스

  • 보통 Json 형태로 데이터를 저장하며 문서(document), key-value로 이루어짐
  • 스키마를 유연하게 변경할 수 있어 빠르게 개발할 수 있음

데이터 모델

  • 컬렉션, 문서, 필드로 이루어진다.
    • 이름은 서로 중복될 수 없다.
  • 컬렉션 안에 문서, 문서 안에 필드 or 컬렉션
  • 필드는 key-value 형태이다.
    • value의 타입은 string, number, boolean, map, array, null ,timestamp, geopoint, reference가 있다.
      • map : 여러 필드를 가질 수 있음
      • array : 여러 유형(타입)의 값을 가질 수 있음
      • timestamp : 날짜+시간
      • geopoint : 위도+경도
      • reference : Firestore datbase 내 다른 문서의 경로

gradle

프로젝트의 build.gradle에 의존성 추가

buildscript {
    dependencies {
        classpath 'com.google.gms:google-services:4.3.14'
    }
}

사용할 모듈(app)의 build.gradle에 id 및 의존성 추가

plugins {
		.....
    id 'com.google.gms.google-services'
}
dependencies {
		.......
    implementation platform ('com.google.firebase:firebase-bom:31.0.3')
    implementation 'com.google.firebase:firebase-firestore-ktx'
}

BoM(Bill of Materials)을 사용하면 BoM에 선언된 개별 라이브러리 버전을 자동으로 매핑해서 가져온다.

만약 Firebase의 여러 라이브러리를 사용해야 하고 각각의 버전을 직접 관리하고 싶다면 BOM 없이 직접 선언하면 된다.

dependencies {
		.......
    implementation 'com.google.firebase:firebase-firestore-ktx:24.4.0'
}

마지막으로 Firebase에 앱을 등록하면 받을 수 있는 google-services.json을 사용할 모듈의 최상단에 넣어줘야 한다.

사용법

db 객체 초기화

// 초기화 후 사용
val db = Firebase.firestore
// 내부 코드

val Firebase.firestore: FirebaseFirestore
    get() = FirebaseFirestore.getInstance()

/* ------------ */

@NonNull
  public static FirebaseFirestore getInstance() {
    FirebaseApp app = FirebaseApp.getInstance();
    if (app == null) {
      throw new IllegalStateException("You must call FirebaseApp.initializeApp first.");
    }
    return getInstance(app, DatabaseId.DEFAULT_DATABASE_ID);
  }
  • 내부에서 Singleton으로 객체를 관리하고 있다.

set, add, update

데이터 지정

val user1 = hashMapOf("first" to "hello", "second" to "world", "세번째" to "데이터")

data class User(val name: String, val team: String)
val user2 = User("김이박", "부스트")

data class Data(val key:String)
val user3 = hashMapOf("first" to "hello!", Data("value!"))
  • 다양한 방식으로 입력 데이터를 지정할 수 있다.
    • update 메소드는 객체를 사용할 수 없고 map을 사용해야 한다.

set

db.collection("users").document("doc")
		.set("first" to "hello", "second" to "world")

db.collection("users").document("doc")
		.set(mapOf("first" to "value"), SetOptions.merge())
  • users/doc 에 데이터를 저장한다.
    • 이미 doc이 있으면 데이터를 덮어쓰며 기존 값은 모두 제거된다.
    • SetOptions.merge() 를 사용하면 기존 데이터와 병합한다.

add

db.collection("users").add(user1)

db.collection("users").document().set(user1)

// -------------------------------

fun document(): DocumentReference {
	  return document(Util.autoId());
}
  • users 컬렉션에 자동으로 생성된 ID로 문서를 생성한다.
    • 경로는 users/{무작위 id} 가 된다.
  • set을 사용할 때 document id를 지정하지 않는 것과 같다.

update

db.collection("users").document("doc")
		.update(mapOf("first" to "hi!!!!"))

db.collection("users").document("doc")
		.update("first", "hi!!!!")

db.collection("users").document("doc")
		.update("location", "seoul")
  • 기존 데이터의 값을 변경한다.
    • 해당하는 이름의 필드가 없으면 필드를 생성해서 저장한다.
  • document가 없으면 생성하지 않는다.
// Atomically add a new region to the "regions" array field.
washingtonRef.update("regions", FieldValue.arrayUnion("greater_virginia"))

// Atomically remove a region from the "regions" array field.
washingtonRef.update("regions", FieldValue.arrayRemove("east_coast"))

// Atomically increment the population of the city by 50.
washingtonRef.update("population", FieldValue.increment(50))
  • 값이 배열일 때 arrayUnionarrayRemove 로 배열에 데이터를 추가하거나 제거할 수 있다.
  • 값이 숫자일 때 increment 로 값을 증가시킬 수 있다.
    • 필드가 없거나 값이 숫자가 아닌 경우 입력한 값을 저장한다.

get, where

get

db.collection("cities").document("SF").get()
    .addOnSuccessListener { documentSnapshot->
        if (documentSnapshot!= null) {
            Log.d(TAG, "DocumentSnapshot data: ${documentSnapshot.data}")
        } else {
            Log.d(TAG, "No such document")
        }
    }
    .addOnFailureListener { exception ->
        Log.d(TAG, "get failed with ", exception)
    }

/* --------------------------- */

db.collection("cities")
		.get()
    .addOnSuccessListener { result ->
        for (document in result) {
            Log.d(TAG, "${document.id} => ${document.data}")
        }
    }
  • 조건에 맞는 데이터를 모두 가져온다.
    • collection 이나 document 가 존재하지 않으면 success 이지만 결과가 null 이다.
  • document 를 지정하지 않으면 해당 collection 의 모든 문서를 가져온다.
  • 결과가 여러개일 때 반복문을 사용해 탐색할 수 있다.

Source

val source = Source.CACHE

docRef.get(source)
  • DEFAULT , SERVER , CACHE 를 지원한다.
    • DEFAULT : 항상 서버에서 데이터를 가져오며, 오프라인 일 때 캐시에 저장된 데이터를 사용한다.
    • SERVER : 항상 서버에서 데이터를 가져오며, 오프라인 일 때 오류를 발생시킨다.
    • CACHE : 캐시된 데이터가 있으면 그 데이터를 사용한다.

toObject

documentSnapshot.toObject<City>()
documentSnapshot.toObject(City::class.java)
  • 원하는 객체에 mapping 시킬 수 있다.
  • 프로퍼티는 var을 사용해야 하며 초기값을 지정해야 한다.
  • 프로퍼티와 같은 이름의 필드가 입력되지 않은 경우 초기값으로 저장된다.

where

  • 연산 종류
    • < less than
    • <= less than or equal to
    • == equal to
    • > greater than
    • >= greater than or equal to
    • [!= not equal to](https://firebase.google.com/docs/firestore/query-data/queries#not_equal)
    • [array-contains](https://firebase.google.com/docs/firestore/query-data/queries#array_membership)
    • [array-contains-any](https://firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any)
    • [in](https://firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any)
    • [not-in](https://firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any)
db.collection("cities")
		.whereEqualTo("capital", true)
		.get()

db.collection("cities")
		.whereArrayContains("regions", "west_coast")
  • 다양한 기능의 함수를 지원한다.

PropertyName

data class User(
    @set:PropertyName("name")
    @get:PropertyName("name")
    var userName: String = "",
    var team: String = ""
)
  • get과 set을 할 때 Firestore에서 사용하는 이름을 각각 지정할 수 있다.
    • get, set 없이 PropertyName("~~~")을 사용하면 안 된다.
  • 이름의 시작이 is 인 경우 해당 변수에 @field:JvmField 를 추가해야 한다.

addOnSuccessListener, addOnFailureListener

db.collection("cities")
    .add(data)
    .addOnSuccessListener { documentReference ->
        Log.d(TAG, "DocumentSnapshot written with ID: ${documentReference.id}")
    }
    .addOnFailureListener { e ->
        Log.w(TAG, "Error adding document", e)
    }
  • 메소드의 성공, 실패를 나누어서 처리할 수 있다.
  • addOnFailureListener 를 사용하면 실패해도 앱이 종료되지 않는다.

참고 자료

Firestore | Firebase
NoSQL이란 무엇인가? 대량데이터 동시처리위한 DBMS 종류와 특징 - SAMSUNG SDS
NoSQL이란? - Amazon

profile
사람을 위한 개발자

0개의 댓글