데이터베이스 쓰기
데이터베이스 읽기


유니티패키지를 추가하고 SDK도 새로 받아서 기존의 google-services.json와 교체해야한다.
그리고 유니티에서 데이터베이스를 사용하기 전
CheckAndFixDependenciesAsync() 에서 파이어베이스를 사용가능 체크를 한 후
static 변수에 DB = FirebaseDatabase.DefaultInstance; 로 데이터베이스의 인스턴스를 할당했다.

데이터베이스에 데이터를 저장하는 함수는 총 5가지이며, 매개변수로는 주로 Object 타입을 받는다.
저장할 수 있는 자료형은 아래와 같다.
- string
- long
- double
- bool
- Dictionary< string, object >
- List< object >
매개변수로 object 타입을 받으며, 이 데이터를 해당 경로에 덮어쓴다.
// RootReference = 최상위 부모
DatabaseReference reference = FirebaseManager.DB.RootReference;
reference.SetValueAsync(new List<string>() { "Test1", "Test2", "Test3" });
reference.SetValueAsync(new List<string>() { "Test4", "Test5" });
reference 경로에 리스트를 두 번 저장하면 어떻게 될까?
Test1, Test2, Test3 이 먼저 저장되고, 그 위에 Test4, Test5 가 저장돼서
Test4, Test5, Test3 이 된다고 생각할 수 있지만,

결과는 Test4, Test5 만 저장된다.
그 이유는 SetValueAsync() 는 기존 데이터를 삭제하고 새 값으로 덮어쓰기 때문이다.
즉, Test1, Test2, Test3 는 삭제되고 Test4, Test5 가 새로 저장된다.
매개변수로 string(JSON) 타입을 받으며, 해당 경로에 JSON 데이터를 덮어쓴다.
// 테스트 클래스들
[Serializable]
public class TestClass
{
public string UserName;
public int Level;
public string Class;
public int Hp;
public List<Inventory> Inventory;
}
[Serializable]
public class Inventory
{
public string ItemName;
public int ItemCount;
}
_testClass = new()
{
UserName = "Clean",
Level = 99,
Class = "전사",
Hp = 104,
Inventory = new()
{
new () { ItemName = "사과", ItemCount = 5, },
new () { ItemName = "레몬", ItemCount = 10, },
}
};
DatabaseReference reference = FirebaseManager.DB.RootReference;
reference.SetRawJsonValueAsync(JsonUtility.ToJson(_testClass)); // JSON 으로 변환

클래스나 구조체도 JSON 구조로 바꾸기 때문에 저장할 수 있고,
List<Dictionary<string, object>> 같은 구조는 사용할 수 없기 때문에
클래스나 구조체로 중간 단계를 만들어서 사용하면 된다.
또한, DatabaseReference userInfo = reference.Child("UserData").Child(user.UserId) 와 같이
root/UserData/UID 주소로 저장하면 UserData 폴더에 각 유저들의 ID로 저장할 수 있다.
딕셔너리의 Key(string)는 경로, Value(object)는 저장할 값이며,
해당 경로에 있는 데이터만 부분적으로 수정한다.
DatabaseReference reference = FirebaseManager.DB.RootReference;
Dictionary<string, object> data = new();
data["UserName"] = "클린";
data["/Class"] = "도적";
data["/Inventory/0/ItemCount"] = 20;
reference.UpdateChildrenAsync(data);

덮어쓰는 SetValueAsync() 와 SetRawJsonValueAsync() 와 다르게
데이터베이스에 있는 Key에 해당하는 경로의 값만 수정할 수 있다.
Key에 경로인 '/' 를 넣든 안넣든 경로는 reference/UserName, reference/Class 가 된다.
그리고 Key는 결국 경로라 .Child() 를 사용해도 되지만, '/' 로 접근할 수 있다.
DatabaseReference reference = FirebaseManager.DB.RootReference;
reference.RunTransaction(task =>
{
var test = task.Value;
Debug.Log(test);
return TransactionResult.Success(task);
});
이런식으로 디버그 찍으면서 보고있는데.... 값이 하나도 안온다 왜이러지?
해당 경로의 데이터를 비동기로 읽어온다.
결과는task.IsFaulted, task.IsCompleted, task.Result등을 통해 알 수 있고,
DataSnapshot 타입에 할당하여 사용한다.

DatabaseReference reference = FirebaseManager.DB.RootReference;
reference.GetValueAsync()
.ContinueWithOnMainThread(task =>
{
if (task.IsFaulted)
{
Debug.LogError("읽기 실패");
return;
}
DataSnapshot snapshot = task.Result;
});
읽어온 데이터를 DataSnapshot 타입 변수에 할당하고, snapshot.Value 로 읽어온 데이터를 알 수 있다.
DataSnapshot snapshot = task.Result;
if (snapshot.Exists)
{
Dictionary<string, object> data = snapshot.Value as Dictionary<string, object>;
if (data != null)
{
foreach (var kvp in data)
{
Debug.Log($"{kvp.Key} : {kvp.Value}");
}
}
}
DataSnapshot snapshot = task.Result;
string json = snapshot.GetRawJsonValue();
TestClass data = JsonUtility.FromJson<TestClass>(json);
Debug.Log($"이름: {data.UserName}, 레벨: {data.Level}");
snapshot.GetRawJsonValue(); 을 통해 데이터를 JSON 구조로 받아올 수 있으며,
JsonUtility.FromJson<T>() 로 다시 클래스로 변환할 수 있다.