웹에서 데이터 목록 다루기

데이터베이스 참조 가져오기

데이터베이스에서 데이터를 읽거나 쓰려면 firebase.database.Reference 인스턴스가 필요합니다.

웹 모듈식 API

import { getDatabase } from "firebase/database";

const database = getDatabase();

웹 네임스페이스화된 API

var database = firebase.database();

목록 읽기 및 쓰기

데이터 목록에 추가

멀티 사용자 애플리케이션에서 push() 메서드를 사용하여 목록에 데이터를 추가합니다. push() 메서드는 지정된 Firebase 참조에 새 하위 요소가 추가될 때마다 고유 키를 생성합니다. 목록의 새 요소마다 이러한 자동 생성 키를 사용하면 여러 클라이언트에서 쓰기 충돌 없이 동시에 같은 위치에 하위 요소를 추가할 수 있습니다. push()가 생성하는 고유 키는 타임스탬프에 기반하므로 목록 항목은 시간순으로 자동 정렬됩니다.

push() 메서드가 반환하는 새 데이터에 대한 참조를 사용하여 하위 요소의 자동 생성 키 값을 가져오거나 하위 데이터를 설정할 수 있습니다. push() 참조의 .key 속성에는 자동 생성 키가 포함됩니다.

이러한 자동 생성 키를 사용하면 데이터 구조의 평면화 작업이 단순해집니다. 자세한 내용은 데이터 팬아웃 예시를 참조하세요.

예를 들면 push()를 사용하여 소셜 애플리케이션의 게시물 목록에 새 게시물을 추가할 수 있습니다.

웹 모듈식 API

import { getDatabase, ref, push, set } from "firebase/database";

// Create a new post reference with an auto-generated id
const db = getDatabase();
const postListRef = ref(db, 'posts');
const newPostRef = push(postListRef);
set(newPostRef, {
    // ...
});

웹 네임스페이스화된 API

// Create a new post reference with an auto-generated id
var postListRef = firebase.database().ref('posts');
var newPostRef = postListRef.push();
newPostRef.set({
    // ...
});

하위 이벤트 수신 대기

하위 이벤트는 노드의 하위 요소에서 발생하는 특정 작업에 대한 응답으로 트리거됩니다. 하위 요소가 push() 메서드를 통해 새로 추가되거나 update() 메서드를 통해 업데이트되는 경우가 그 예시입니다.

이벤트 일반적인 용도
child_added 항목 목록을 검색하거나 항목 목록에 대한 추가를 수신 대기합니다. 이 이벤트는 기존 하위 요소마다 한 번씩 트리거된 후 지정된 경로에 하위 요소가 새로 추가될 때마다 다시 트리거됩니다. 리스너에는 새 하위 요소의 데이터를 포함하는 스냅샷이 전달됩니다.
child_changed 목록의 항목에 대한 변경사항을 수신 대기합니다. 이 이벤트는 하위 노드가 수정될 때마다 트리거됩니다. 여기에는 하위 노드의 하위 요소에 대한 수정이 포함됩니다. 이벤트 리스너에 전달되는 스냅샷에는 하위 요소의 업데이트된 데이터가 포함됩니다.
child_removed 목록의 항목 삭제를 수신 대기합니다. 이 이벤트는 바로 아래 하위 요소가 삭제될 때 트리거됩니다. 콜백 블록에 전달되는 스냅샷에는 삭제된 하위 요소의 데이터가 포함됩니다.
child_moved 순서가 지정된 목록의 항목 순서 변경사항을 수신 대기합니다. child_moved 이벤트는 항상 현재의 정렬 기준 메서드에 따라 항목 순서를 변경하도록 한 child_changed 이벤트 뒤에 나옵니다.

이러한 메서드는 데이터베이스의 특정 노드에 대한 변경사항을 수신 대기하는 데 유용할 수 있습니다. 예를 들어 소셜 미디어 블로깅 앱은 아래와 같이 이러한 메서드를 함께 사용하여 게시물의 댓글 활동을 모니터링할 수 있습니다.

웹 모듈식 API

import { getDatabase, ref, onChildAdded, onChildChanged, onChildRemoved } from "firebase/database";

const db = getDatabase();
const commentsRef = ref(db, 'post-comments/' + postId);
onChildAdded(commentsRef, (data) => {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

onChildChanged(commentsRef, (data) => {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

onChildRemoved(commentsRef, (data) => {
  deleteComment(postElement, data.key);
});

웹 네임스페이스화된 API

var commentsRef = firebase.database().ref('post-comments/' + postId);
commentsRef.on('child_added', (data) => {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_changed', (data) => {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_removed', (data) => {
  deleteComment(postElement, data.key);
});

값 이벤트 수신 대기

데이터 목록 읽기에 권장되는 방법은 하위 이벤트를 수신 대기하는 것이지만 상황에 따라서는 목록 참조의 값 이벤트를 수신 대기하는 방법이 유용합니다.

데이터 목록에 value 관찰자를 연결하면 전체 데이터 목록이 단일 스냅샷으로 반환되며, 이를 루프 처리하여 개별 하위 요소에 액세스할 수 있습니다.

쿼리에 일치하는 항목이 단 한 개인 경우에도 스냅샷은 목록으로 표시됩니다. 단지 항목이 한 개 있을 뿐입니다. 항목에 액세스하려면 결과를 루프 처리해야 합니다.

웹 모듈식 API

import { getDatabase, ref, onValue } from "firebase/database";

const db = getDatabase();
const dbRef = ref(db, '/a/b/c');

onValue(dbRef, (snapshot) => {
  snapshot.forEach((childSnapshot) => {
    const childKey = childSnapshot.key;
    const childData = childSnapshot.val();
    // ...
  });
}, {
  onlyOnce: true
});

웹 네임스페이스화된 API

ref.once('value', (snapshot) => {
  snapshot.forEach((childSnapshot) => {
    var childKey = childSnapshot.key;
    var childData = childSnapshot.val();
    // ...
  });
});

하위 추가 이벤트를 추가로 수신 대기하는 대신 한 번의 작업으로 목록의 모든 하위 요소를 가져오려는 경우 이 패턴이 유용할 수 있습니다.

데이터 정렬 및 필터링

실시간 데이터베이스의 Query 클래스를 사용하여 키, 값 또는 하위 요소 값으로 정렬된 데이터를 검색할 수 있습니다. 정렬된 결과를 특정 개수로 필터링하거나 키 또는 값 범위에 따라 필터링할 수도 있습니다.

데이터 정렬

정렬된 데이터를 검색하려면 우선 정렬 기준 메서드 중 하나를 지정하여 결과를 어떤 순서로 정렬할지 결정합니다.

메서드 용도
orderByChild() 지정된 하위 키 또는 중첩된 하위 경로의 값에 따라 결과를 정렬합니다.
orderByKey() 하위 키에 따라 결과를 정렬합니다.
orderByValue() 하위 값에 따라 결과를 정렬합니다.

정렬 기준 메서드는 한번에 하나만 사용할 수 있습니다. 동일한 쿼리에서 정렬 기준 메서드를 여러 번 호출하면 오류가 발생합니다.

다음 예시에서는 별표 수를 기준으로 사용자의 최상위 게시물 목록을 검색하는 방법을 보여줍니다.

웹 모듈식 API

import { getDatabase, ref, query, orderByChild } from "firebase/database";
import { getAuth } from "firebase/auth";

const db = getDatabase();
const auth = getAuth();

const myUserId = auth.currentUser.uid;
const topUserPostsRef = query(ref(db, 'user-posts/' + myUserId), orderByChild('starCount'));

웹 네임스페이스화된 API

var myUserId = firebase.auth().currentUser.uid;
var topUserPostsRef = firebase.database().ref('user-posts/' + myUserId).orderByChild('starCount');

여기에서는 쿼리를 하위 리스너와 함께 사용하여 사용자 ID를 기준으로 데이터베이스의 특정 경로에 있는 사용자의 게시물을 각 게시물이 받는 별표 수에 따라 정렬한 결과를 클라이언트와 동기화하도록 쿼리를 정의합니다. 이와 같이 ID를 색인 키로 사용하는 기법을 데이터 팬아웃이라고 합니다. 자세한 내용은 데이터베이스 구조화를 참조하세요.

orderByChild() 메서드를 호출할 때는 결과를 정렬하는 기준이 될 하위 키를 지정합니다. 여기에서는 각 게시물의 "starCount" 하위 요소 값에 따라 게시물이 정렬됩니다. 다음과 같은 데이터가 있다면 중첩된 하위 요소에 따라 쿼리를 정렬할 수도 있습니다.

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

이 예시에서는 orderByChild() 호출에서 중첩된 하위 요소에 대한 상대 경로를 지정하여 metrics 키 아래에 중첩된 값에 따라 목록 요소를 정렬할 수 있습니다.

웹 모듈식 API

import { getDatabase, ref, query, orderByChild } from "firebase/database";

const db = getDatabase();
const mostViewedPosts = query(ref(db, 'posts'), orderByChild('metrics/views'));

웹 네임스페이스화된 API

var mostViewedPosts = firebase.database().ref('posts').orderByChild('metrics/views');

다른 데이터 유형을 정렬하는 방법에 대한 자세한 내용은 쿼리 데이터 정렬 방법을 참조하세요.

데이터 필터링

데이터를 필터링하려면 제한 또는 범위 메서드를 정렬 기준 메서드와 조합하여 쿼리를 작성합니다.

메서드 용도
limitToFirst() 정렬된 결과 목록의 시작 부분부터 반환할 최대 항목 수를 설정합니다.
limitToLast() 정렬된 결과 목록의 맨 끝 부분부터 반환할 최대 항목 수를 설정합니다.
startAt() 선택한 정렬 기준 메서드에 따라 지정된 키 또는 값보다 크거나 같은 항목을 반환합니다.
startAfter() 선택한 정렬 기준 메서드에 따라 지정된 키 또는 값보다 큰 항목을 반환합니다.
endAt() 선택한 정렬 기준 메서드에 따라 지정된 키 또는 값보다 작거나 같은 항목을 반환합니다.
endBefore() 선택한 정렬 기준 메서드에 따라 지정된 키 또는 값보다 작은 항목을 반환합니다.
equalTo() 선택한 정렬 기준 메서드에 따라 지정된 키 또는 값과 동일한 항목을 반환합니다.

정렬 기준 메서드와 달리 여러 개의 제한 또는 범위 함수를 조합할 수 있습니다. 예를 들어 startAt()endAt() 메서드를 조합하여 결과를 지정된 값 범위로 제한할 수 있습니다.

결과 수 제한

limitToFirst()limitToLast() 메서드를 사용하여 특정 이벤트에서 동기화할 하위 요소의 최대 개수를 설정할 수 있습니다. 예를 들어 limitToFirst()를 사용하여 제한을 100개로 설정하면 처음에 최대 100개의 child_added 이벤트만 수신합니다. Firebase 데이터베이스에 저장된 항목이 100개 미만이면 모든 항목에 child_added 이벤트가 발생합니다.

항목이 변경됨에 따라 쿼리에 새로 포함되는 항목에 대해 child_added 이벤트, 쿼리에서 제외되는 항목에 대해 child_removed 이벤트가 수신되며 총 개수는 100개로 유지됩니다.

다음 예시에서는 블로깅 앱이 모든 사용자의 게시물 중 최근 100개의 목록을 검색하는 쿼리를 정의하는 방법을 보여줍니다.

웹 모듈식 API

import { getDatabase, ref, query, limitToLast } from "firebase/database";

const db = getDatabase();
const recentPostsRef = query(ref(db, 'posts'), limitToLast(100));

웹 네임스페이스화된 API

var recentPostsRef = firebase.database().ref('posts').limitToLast(100);

이 예시에서는 쿼리를 정의하기만 하므로 데이터를 실제로 동기화하려면 리스너를 연결해야 합니다.

키 또는 값으로 필터링

startAt(), startAfter(), endAt(), endBefore(), equalTo()를 사용하여 쿼리의 시작, 종료, 동일 지점을 임의로 선택할 수 있습니다. 이 메서드는 특정 값을 갖는 하위 요소로 데이터를 페이지로 나누거나 항목을 찾는 데 유용합니다.

쿼리 데이터 정렬 방법

이 섹션에서는 Query 클래스의 각 정렬 기준 메서드에 따라 데이터를 정렬하는 방법을 설명합니다.

orderByChild

orderByChild()를 사용하면 지정된 하위 키를 포함하는 데이터가 다음과 같이 정렬됩니다.

  1. 지정된 하위 키의 값이 null인 하위 요소가 맨 처음에 옵니다.
  2. 지정된 하위 키의 값이 false인 하위 요소가 그다음에 옵니다. 값이 false인 하위 요소가 여러 개인 경우 키에 따라 사전순으로 정렬됩니다.
  3. 지정된 하위 키의 값이 true인 하위 요소가 그다음에 옵니다. 값이 true인 하위 요소가 여러 개인 경우 키에 따라 사전순으로 정렬됩니다.
  4. 숫자 값이 있는 하위 요소가 그다음에 나오며 오름차순으로 정렬됩니다. 지정된 하위 노드의 숫자 값이 동일한 하위 요소가 여러 개면 키에 따라 정렬됩니다.
  5. 숫자 다음에는 문자열이 나오며 사전순, 오름차순으로 정렬됩니다. 지정된 하위 노드의 값이 동일한 하위 요소가 여러 개면 키에 따라 사전순으로 정렬됩니다.
  6. 마지막으로 객체가 나오며 키에 따라 사전순, 오름차순으로 정렬됩니다.

orderByKey

orderByKey()를 사용하여 데이터를 정렬하면 데이터가 오름차순(키 기준)으로 반환됩니다.

  1. 키가 32비트 정수로 파싱될 수 있는 하위 요소가 맨 처음에 나오며 오름차순으로 정렬됩니다.
  2. 키가 문자열 값인 하위 요소가 그다음에 나오며 오름차순(사전순)으로 정렬됩니다.

orderByValue

orderByValue()를 사용하면 하위 요소가 값에 따라 정렬됩니다. 정렬 기준은 orderByChild()와 동일하지만 지정된 하위 키의 값 대신 노드의 값이 사용된다는 점이 다릅니다.

리스너 분리

Firebase 데이터베이스 참조에 대해 off() 메서드를 호출하면 콜백이 삭제됩니다.

리스너 하나를 삭제하려면 off()에 매개변수로 전달합니다. 한 위치에서 인수 없이 off()를 호출하면 해당 위치의 모든 리스너가 삭제됩니다.

상위 리스너에 off()를 호출해도 하위 노드에 등록된 리스너가 자동으로 삭제되지 않습니다. 하위 리스너에도 off()를 호출하여 콜백을 삭제해야 합니다.

다음 단계