TIL.17 | Database / NoSQL / firebase, firestore 사용하기

원용현·2023년 11월 16일
0

TIL

목록 보기
17/18

프로젝트를 진행하면서 express 서버를 통해서 데이터를 가져와 프론트에 뿌려주는 작업을 진행하고 있던 도중에 프론트에서 새로운 데이터를 만들어서 express 백엔드 서버로 넘겨주었을 때, 시스템이 실행 중일 때는 문제 없지만, 재실행이 하면 만들었던 데이터가 사라지는 것을 확인하였다. 데이터가 목록에 계속 남아있는 것을 원했기 때문에 관련 내용을 찾아보던 중에 data를 가져와서 변수에 저장하고 해당 변수를 조작하는 것은 원본에 영향을 끼칠 수 없다는 것을 알게 되었다.

따라서 해당 데이터를 남기기 위해서 express와 Database를 연동할 필요가 생겼다.

Database

데이터베이스는 데이터들의 집합으로 이런 데이터베이스를 관리하는 시스템을 DBMS(Database Management System)이라 한다. 데이터베이스에는 MySQL, Oracle, SQLite, MariaDB 등 다양한 종류가 있으니 자신의 프로젝트의 성격에 따라 오픈소스, 상용, pc용, 모바일용 등의 것을 알아보고 결정한다.

DBMS의 대부분은 RDBMS(관계형 DBMS)를 채택하는데 RDBMS의 데이터베이스는 테이블(table)이라는 최소 단위로 구성되는데, 이 테이블은 하나 이상의 행(row)과 열(column)로 구성된다.

흔히 문서 편집 프로그램의 표나 엑셀을 사용해봤다면 테이블의 형태에 대해서는 쉽게 이해할 수 있을 것이다.

SQL(Structured Query Language)

관계형 데이터베이스에서는 테이블 안의 데이터들을 건드리기 위해서, 흔히 CRUD라고 불리는 작업을 진행하기 위해서 SQL이라는 언어를 사용한다.

  • create
  • read
  • update
  • delete

이 글에서 사용하는 Firebase의 firestore의 경우에는 데이터베이스이지만, 관계형 데이터베이스의 시스템을 채택하지 않는 NoSQL의 방식을 사용하기 때문에 NoSQL로 넘어가도록 하겠다.

NoSQL

관계형 데이터베이스는 초기 데이터를 관리하는 최고의 시스템으로 채택되어 많은 DBMS에서 사용되었다.

NoSQL이 처음 등장했을 때도 기업의 ERP 등 데이터의 정확성과 SQL의 편이성 때문에 관계형 데이터베이스가 주로 사용되었으니 정형데이터보다는 비정형데이터의 양이 많아졌고, 비정형데이터를 관리하기 편한 NoSQL이 각광받게 되었다.

NoSQL 데이터베이스는 단순 검색 및 추가 작업에 있어서 매우 최적화된 키 값 저장 기법을 사용하여 응답속도나 처리 효율 등에 있어서 매우 뛰어난 성능을 나타낸다.

여기서는 google에서 제공하는 firebase라는 NoSQL의 firestore를 사용할 것이다.

firebase

Firebase는 구글에서 제공하는 모바일 앱/웹을 위한 플랫폼이다. Firebase는 인증(authentication), 데이터베이스(firestore database, realtime database), 스토리지, 푸시 알림, 호스팅, Function 등 여러 기능을 제공하기 때문에 개발자가 직접 일일이 기능을 개발할 필요가 없다. 클라우드 서비스 형태로 백엔드 서버를 제공하여 따로 백엔드 서버를 구입할 필요도 없다.

일정 용량, 일일 제한으로 무료 서비스를 제공하므로 실무보다는 프로젝트에서 사용하기 좋은 플랫폼이다.

firestore

구글에서 제공하는 NoSQL 데이터베이스 서비스로 사용자와 기기간의 데이터 실시간 동기화가 가능하다.

firestore는 컬렉션으로 정리되는 문서에 데이터를 저장하는데 각 문서는 형태가 정해지지 않은 데이터를 저장하는데, 그 외에도 또 다른 컬렉션을 가리키는 것이 가능하다.

express에서 firestore 사용하기

기본적으로 firestore는 우리가 생각하는 다양한 프로그래밍 언어에서 사용할 수 있기 때문에 javascript로 작성되는 node.js에서 사용하는 방법에 대해서 공부하면된다.

firebase에서 doc을 살펴보면 Cloud Firestore 시작하기에서 firestore를 사용하는 방법에 대해서 자세하게 설명하고 있다.

https://firebase.google.com/docs/firestore/quickstart?hl=ko

자신의 개발 환경에 따라서 코드를 작성하는데 이 글에서는 express를 통해서 firestore를 사용할 것이기 때문에 자체 서버 코드 부분을 참고하였고 개발 환경에 맞게 코드를 고쳐서 사용하였다.

초기화

  • firestore를 사용하기 위한 기본 세팅을 초기화해준다. firebase 라이브러리와 firebase-admin 라이브러리를 설치한다.
    Firebase를 초기화하여 사용하려는 제품의 SDK를 연결하기 위해서 firebase 라이브러리를 설치하고 컬렉션과 문서에 접근하여 firestore를 수정하기 위해서 firebase-admin 라이브러리를 설치한다.

    yarn add firebase firebase-admin

  • firebase에서 생성한 프로젝트 설정에 들어가 서비스 계정의 비공개 키를 생성한다.
    비공개 키는 json 파일로 다운로드가 되는데 해당 파일을 프로젝트로 이동하여 프로젝트에서 사용한다.

    프로젝트 개요 오른쪽의 톱니 -> 프로젝트 설정 -> 서비스 계정 -> 하단의 새 비공개 키 생성

{
  "type": "",
  "project_id": "",
  "private_key_id": "",
  "private_key": "",
  "client_email": "",
  "client_id": "",
  "auth_uri": "",
  "token_uri": "",
  "auth_provider_x509_cert_url": "",
  "client_x509_cert_url": "",
  "universe_domain": ""
}
  • 프로젝트 내의 코드
    json 파일을 import 할 때는 assert를 사용해서 import 해 오는 파일의 내용이 json 형태임을 알려야 오류 없이 import 가능하다.
/app.js

import { initializeApp, applicationDefault, cert } from 'firebase-admin/app';
import { getFirestore, Timestamp, FieldValue, Filter } from 'firebase-admin/firestore';
import serviceAccount from './path/to/serviceAccountKey.json' assert { type: "json" };

initializeApp({
  credential: cert(serviceAccount)
});
const db = getFirestore();

위의 설정으로 생성한 프로젝트의 컬렉션 및 문서에 접근이 가능하다.

데이터 추가

데이터의 추가는 연결된 db에서 컬렉션, 문서에 set 메소드를 사용해서 가능하다. 연결된 함수와 async-await를 걸어주도록 한다.

const docRef = db.collection('users').doc('profile');

await docRef.set({
  name: 'kim',
  age: '18'
});

doc의 id 값을 의미가 없는 uuid로 만들기 위해서는 set이 아닌 add 메소드를 통해 데이터를 추가한다.

const res = await db.collection('users').add({
  name: 'kim',
  age: '18'
});

데이터 가져오기

데이터를 가져올 때는 컬렉션에 포함되어 있는 문서들 전체를 가져올 수도 있고, 컬렉션의 문서 하나만을 선택해서 데이터를 가져올 수도 있다.

기본적으로 firestore의 컬렉션이나 문서에 연결하여 get 메소드를 통해서 데이터를 얻어온다.

컬렉션과 문서들의 id를 정확히 알아야 해당 데이터를 가져오는 것이 가능하다.

  • 컬렉션의 문서 전체 가져오기
    컬렉션의 id를 통해서 컬렉션 내부의 문서들을 가져올 수 있다. 문서 전체는 배열로 가져오기 때문에 forEach로 각각의 문서를 뽑아내고 그 안의 id와 data를 가져오면 데이터를 얻을 수 있다.
const snapshot = await db.collection('users').get();

snapshot.forEach((doc) => {
  console.log(doc.id, '=>', doc.data());
});
  • 특정 문서 가져오기
    컬렉션의 id와 그 내부의 문서 id로 연결하여 해당 문서의 데이터를 얻어온다.
const docRef = db.collection('users').doc('profile');
const doc = await docRef.get();
if (!doc.exists) {
  console.log('No such document!');
} else {
  console.log('Document data:', doc.data());
}
  • 쿼리로 특정 문서들 가져오기
    Firestore의 컬렉션과 연결하여 where 메소드를 통해서 쿼리연산자를 사용해 일치하는 데이터가 존재하는 문서들을 가져올 수 있다. 해당 조건을 만족하는 문서 전체를 가져온다. where 메소드를 여러개 연결하여 복합 쿼리를 실행할 수 있다.
    or 연산 역시 사용이 가능한데 사용 방법이 조금 다름을 유의하여 작성한다.
const queryRef1 = db.collection('users').where('name', '==', '철수').get();
const queryRef2 = db.collection('users').where('name', '==', '철수').get();

const queryRef3 = db.collection('users')
  .where(
    Filter.or(
      Filter.where('name '==', '철수'),
      Filter.where('population', '>=', 1000000)
    )
  )
  .get();
쿼리 연산자
< 미만
<= 작거나 같음
== 같음
>\> 보다 큼
>= 이상
!= 같지 않음
array-contains
array-contains-any
in
not-in
  • 데이터 정렬하여 문서 가져오기
    문서의 데이터들 중에 하나를 선택하여 해당 값을 기준으로 오름, 내림차순으로 정렬이 가능하다. order 메소드를 통해 정렬을 진행하는데 order 메소드를 2개 이상 연속으로 연결하여 2개 이상의 값으로 정렬이 가능하다.
    만약 게시판 같은 것을 제작할 때 등록 순서대로 정렬이 필요하다면 Timestamp를 활용하여 createAt 데이터 필드를 만들어 데이터를 가져올 때 createAt을 내림차순 정렬하여 가져온다.
const orderRef = db.collection('users').orderBy('name', 'desc').get();
const orderRef = db.collection('users').orderBy('age', 'asc').orderBy('name', 'desc').get();
  • 특정 개수의 문서 가져오기
    limit 메소드를 사용하여 컬렉션의 문서를 가져올 때 조건에 맞는 데이터들 중에 정한 개수의 문서만 가져온다.
const limitRef = db.collection('users').orderBy('name').limit(3).get();

링크

기본적인 Firebase의 Firestore 사용법은 위와 같지만 더 자세하고 다양한 사용방법과 Cloud Functions를 사용하면 express를 사용할 필요도 없으니 관련 사항에 대해서는 아래의 링크를 참고하면 될 것 같다.

https://firebase.google.com/docs/firestore/quickstart?hl=ko

0개의 댓글