Firebase Summit에서 발표된 모든 내용을 살펴보고 Firebase로 앱을 빠르게 개발하고 안심하고 앱을 실행하는 방법을 알아보세요. 자세히 알아보기

데이터베이스 구조화

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

시작하기 전에

실시간 데이터베이스 를 사용하려면 먼저 다음을 수행해야 합니다.

  • Unity 프로젝트를 등록하고 Firebase를 사용하도록 구성합니다.

    • Unity 프로젝트에서 이미 Firebase를 사용하고 있다면 이미 Firebase용으로 등록 및 구성되어 있는 것입니다.

    • Unity 프로젝트가 없는 경우 샘플 앱 을 다운로드할 수 있습니다.

  • Firebase Unity SDK (특히 FirebaseDatabase.unitypackage )를 Unity 프로젝트에 추가합니다.

Unity 프로젝트에 Firebase를 추가하려면 Firebase 콘솔 과 열려 있는 Unity 프로젝트 모두의 작업이 필요합니다(예: 콘솔에서 Firebase 구성 파일을 다운로드한 다음 Unity 프로젝트로 이동).

데이터 구조화

이 가이드에서는 Firebase 실시간 데이터베이스에서 JSON 데이터를 구조화하기 위한 권장사항과 데이터 아키텍처의 몇 가지 주요 개념을 다룹니다.

적절하게 구조화된 데이터베이스를 구축하려면 상당한 사전 생각이 필요합니다. 가장 중요한 것은 데이터를 저장하고 나중에 검색하여 해당 프로세스를 최대한 쉽게 수행할 방법을 계획해야 한다는 것입니다.

데이터 구조화: JSON 트리

모든 Firebase 실시간 데이터베이스 데이터는 JSON 객체로 저장됩니다. 데이터베이스를 클라우드 호스팅 JSON 트리로 생각할 수 있습니다. SQL 데이터베이스와 달리 테이블이나 레코드가 없습니다. JSON 트리에 데이터를 추가하면 연결된 키가 있는 기존 JSON 구조의 노드가 됩니다. 사용자 ID 또는 의미 체계 이름과 같은 고유한 키를 제공하거나 Push() 메서드를 사용하여 제공할 수 있습니다.

고유한 키를 만드는 경우 UTF-8로 인코딩되어야 하고 최대 768바이트일 수 있으며 . , $ , # , [ , ] , / 또는 ASCII 제어 문자 0-31 또는 127. 값 자체에도 ASCII 제어 문자를 사용할 수 없습니다.

예를 들어 사용자가 기본 프로필과 연락처 목록을 저장할 수 있는 채팅 응용 프로그램을 생각해 보십시오. 일반적인 사용자 프로필은 /users/$uid 와 같은 경로에 있습니다. 사용자 alovelace 는 다음과 같은 데이터베이스 항목을 가질 수 있습니다.

{
  "users": {
    "alovelace": {
      "name": "Ada Lovelace",
      "contacts": { "ghopper": true },
    },
    "ghopper": { ... },
    "eclarke": { ... }
  }
}

데이터베이스는 JSON 트리를 사용하지만 데이터베이스에 저장된 데이터는 사용 가능한 JSON 유형에 해당하는 특정 기본 유형으로 표시되어 유지 관리가 더 쉬운 코드를 작성하는 데 도움이 될 수 있습니다.

데이터 구조 모범 사례

데이터 중첩 방지

Firebase 실시간 데이터베이스는 최대 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 트리를 클라이언트에 다운로드해야 합니다.

데이터 구조 평면화

데이터가 대신 비정규화라고도 하는 별도의 경로로 분할되는 경우 필요에 따라 별도의 호출에서 효율적으로 다운로드할 수 있습니다. 다음과 같은 평평한 구조를 고려하십시오.

{
  // 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": { ... }
  }
}

이제 대화당 몇 바이트만 다운로드하여 회의실 목록을 반복할 수 있으며 UI에서 회의실을 나열하거나 표시하기 위한 메타데이터를 빠르게 가져옵니다. 메시지를 개별적으로 가져와서 도착할 때 표시할 수 있으므로 UI가 빠르게 응답할 수 있습니다.

확장 가능한 데이터 생성

앱을 빌드할 때 목록의 하위 집합을 다운로드하는 것이 더 나은 경우가 많습니다. 이는 목록에 수천 개의 레코드가 포함된 경우에 특히 일반적입니다. 이 관계가 정적이고 단방향이면 부모 아래에 자식 개체를 중첩할 수 있습니다.

때로는 이 관계가 더 동적이거나 이 데이터를 비정규화해야 할 수도 있습니다. 데이터 검색 에서 설명한 대로 쿼리를 사용하여 데이터의 하위 집합을 검색하여 데이터를 비정규화할 수 있는 경우가 많습니다.

그러나 이것조차 충분하지 않을 수 있습니다. 예를 들어, 사용자와 그룹 간의 양방향 관계를 고려하십시오. 사용자는 그룹에 속할 수 있으며 그룹은 사용자 목록을 구성합니다. 사용자가 속한 그룹을 결정할 때가 되면 상황이 복잡해집니다.

필요한 것은 사용자가 속한 그룹을 나열하고 해당 그룹에 대한 데이터만 가져오는 우아한 방법입니다. 그룹 색인 은 다음과 같이 많은 도움이 될 수 있습니다.

// 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
      }
    },
    ...
  }
}

이것이 Ada의 레코드와 그룹 모두에 관계를 저장하여 일부 데이터를 복제한다는 것을 알 수 있습니다. 이제 alovelace 는 그룹 아래에 색인이 생성되고 techpioneers 는 Ada의 프로필에 나열됩니다. 따라서 그룹에서 Ada를 삭제하려면 두 곳에서 업데이트해야 합니다.

이것은 양방향 관계에 필요한 중복입니다. 이를 통해 사용자 또는 그룹 목록이 수백만으로 확장되거나 실시간 데이터베이스 보안 규칙이 일부 레코드에 대한 액세스를 차단하는 경우에도 Ada의 멤버십을 빠르고 효율적으로 가져올 수 있습니다.

ID를 키로 나열하고 값을 true로 설정하여 데이터를 반전시키는 이 접근 방식을 사용하면 /users/$uid/groups/$group_id 를 읽고 null 인지 확인하는 것처럼 간단하게 키를 확인할 수 있습니다. 인덱스는 데이터를 쿼리하거나 스캔하는 것보다 더 빠르고 훨씬 효율적입니다.

다음 단계