Firebase 에서 사용할 수 있는 DB 종류

  1. RealTimeDatabase
  2. Cloud Firestore

2개가 존재하며 둘다 NoSQL DB이며 실시간으로 데이터가 동기화된다.

자세한 차이점은 데이터베이스 선택: Cloud Firestore 또는 실시간 데이터베이스 에 적혀있다.

 


Database 설정

1. 개발 에서 [Database] 를 선택

 

2. [데이터베이스 만들기] 클릭

 

3. 프로덕션 모드에서 시작

 

4. Cloud Firestore 위치를 asia-east2 로 설정

asia-east2(홍콩) 이며 Firebase 실시간 데이터베이스(Realtime Database) 은 적용되지 않는다. 위치에 대한 자세한 설명

 

5. 데이터베이스가 다 만들어졌다.


RealTimeDatabase 사용

Firebase Admin Realtime Database API 소개

 

Admin Database API 소개  |  Firebase 실시간 데이터베이스

Admin SDK를 사용하면 전체 관리자 권한이나 보다 세밀한 제한된 권한으로 실시간 데이터베이스 데이터를 읽고 쓸 수 있습니다. 이 문서에서는 Firebase 실시간 데이터베이스 액세스를 위해 프로젝트에 Firebase Admin SDK를 추가하는 방법을 설명합니다. Admin SDK 설정 서버에서 Firebase 실시간 데이터베이스를 시작하려면 우선 원하는 언어로 Firebase Admin SDK를 설정해야 합니다. 서버와 같은 관리자 권한 환경에서의

firebase.google.com

 

Realtime Database 설정

 

1. Database 옆 항목에서 [Realtime Database] 를 선택한다.

 

2. [규칙] 을 선택한 후 규칙을 변경한다.

false -> true 로 수정한다.

 

 

DB에 데이터를 넣고 데이터를 불러오는 알아보자.

 

일단, 데이터를 게시판 형태로 DB를 이용해보자.

 

app.js

const postsRouter = require('./routes/posts');

app.use('/posts', postsRouter);

// false 를 true 로 수정
app.use(express.urlencoded({ extended: true }));

 

express.urlencoded 관련 설명 : https://sjh836.tistory.com/154

 

 

routes/rPosts.js

var express = require('express');
var router = express.Router();

const admin = require('firebase-admin');

// firebase Admin 초기화
const firebaseAdmin = admin.initializeApp({
  credential: admin.credential.cert({
      "firebaseAdmin Key"
    }),
  databaseURL: "",
  storageBucket: ""
}, "posts");

const dateFormat = require('dateformat');

///
/// 데이터 베이스 관련
///

router.get('/List', function(req, res, next) {
  firebaseAdmin.database().ref('posts').orderByKey().once('value', function(snapshot) {
    var rows = [];
    snapshot.forEach(function(childSnapshot) {
      var childData = childSnapshot.val();

      childData.postsdate = dateFormat(childData.postsdate, "yyyy-mm-dd");
      rows.push(childData);
    });
    res.render('rPosts/List', {rows: rows});
  });
});

router.get('/Read', function(req, res, next) {
  firebaseAdmin.database().ref('posts/' + req.query.postsno).once('value', function(snapshot) {
    var childData = snapshot.val();

    childData.postsno = snapshot.key;
    childData.postsdate = dateFormat(childData.postsdate, "yyyy-mm-dd");
    res.render('rPosts/Read', {row:childData});
  });
});

router.get('/Write', function(req, res, next) {
  if(!req.query.postsno) {
    res.render('rPosts/Write', {row:""});
    return;
  }

  firebaseAdmin.database().ref('posts/'+req.query.postsno).once('value', function(snapshot) {
    var childData = snapshot.val();

    childData.postsno = snapshot.key;
    res.render('rPosts/Write', {row: childData});
  });
});

router.post('/Save', function(req, res, next) {
  var postData = req.body;

  if (!postData.postsno) {
    postData.postsno = firebaseAdmin.database().ref().child('posts').push().key;
    postData.postsdate = Date.now();
  } else {
    postData.postsdate = Number(postData.postsdate);
  }

  firebaseAdmin.database().ref('posts/' + req.body.postsno).set(
    req.body, function(err) {
      if(err) {
        console.log(err);
      } else {
        console.log(req.body.postsno + " Upload successfully");
      }
    });

    res.redirect('List');
});

router.get('/Delete', function(req, res, next) { 
  firebaseAdmin.database().ref('posts/' + req.query.postsno).remove();

  res.redirect('List');
});

module.exports = router;
const admin = require('firebase-admin');

// firebase Admin 초기화
const firebaseAdmin = admin.initializeApp({
  credential: admin.credential.cert({
      "firebaseAdmin Key"
    }),
  databaseURL: "",
  storageBucket: ""
}, "posts");

 

애플리케이션에서 여러 프로젝트를 사용할일이 있다면 애플리케이션에서 여러 프로젝트 사용 을 참고하여 각 admin.initializeApp 에 이름(Ex - "posts")을 부여 해줘야한다. 하나의 프로젝트에서만 사용할 경우 이름을 부여하지 않아도 된다.

 

// posts 의 데이터를 모두(once) 얻어 온 데이터(snapshot)는 key, Data 로 이루어진 데이터를 받는다.
firebaseAdmin.database().ref('posts').orderByKey().once('value', function(snapshot)

// posts에서 특정 key로 데이터를 전부 받아온다.
firebaseAdmin.database().ref('posts/' + req.query.postsno).once('value', function(snapshot)

// 새로운 key를 받아온다.
postData.postsno = firebaseAdmin.database().ref().child('posts').push().key;

// posts에서 특정 key로 데이터를 입력한다. Key가 겹칠 경우 자동으로 덮어쓴다.
firebaseAdmin.database().ref('posts/' + req.body.postsno).set()

// posts에서 특정 key로 된 데이터를 삭제한다.
firebaseAdmin.database().ref('posts/' + req.query.postsno).remove();

 

ref, once 에 관련된 내용은 아래 링크에서 자세하게 알 수 있다.

Realtime Database 데이터 읽기 및 쓰기

 

 

List.ejs

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Test & MySite</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>

<div id="main">
  <table border="1" style="width:600px">
    <caption>Firebase RealTime Database Sample</caption>
    <colgroup>
      <col width='8%'/>
      <col width='*%' />
      <col width='15%'/>
      <col width='15%'/>
    </colgroup>
    <thead>
      <tr>
        <th>No.</th>
        <th>Title</th>
        <th>Writer</th>
        <th>Date</th>
      </tr>
    </thead>
    <tbody>
      <%
        for(var i=0; i<rows.length; i++) {
      %>
      <tr>
        <td><%=rows.length - i%></td>
        <td><a href='Read?postsno=<%=rows[i].postsno%>'><%=rows[i].poststitle%></a></td>
        <td><%=rows[i].postswriter%></td>
        <td><%=rows[i].postsdate%></td>
      </tr>
      <%
        }
      %>
    </tbody>
  </table>
  <a href="Write">New</a>
</div>
</body>
</html>

 

Read.ejs

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Test & MySite</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
</head>

<body>
    <table border="1" style="width:600px">
      <caption>Firebase RealTime Database Sample</caption>
      <colgroup>
        <col width='15%'/>
        <col width='*%'/>
      </colgroup>
      <tbdoy>
        <tr>
          <td>Writer</td>
          <td><%=row.postswriter%></td>
        </tr>
        <tr>
          <td>Title</td>
          <td><%=row.poststitle%></td>
        </tr>
        <tr>
          <td>Memo</td>
          <td><%=row.postsmemo%></td>
        </tr>
      </tbdoy>
    </table>
    <a href="#" onclick="history.back(-1)">글 목록</a>
    <a href="Delete?postsno=<%=row.postsno%>">삭제</a>
    <a href="Write?postsno=<%=row.postsno%>">수정</a>
</body>
</html>

 

Write.ejs

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Test & MySite</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
</head>

<body>
  <form name="form1" action="Save" method="POST">
    <table border="1" style="width:600px">
      <caption>Firebase RealTime Database Sample</caption>
      <colgroup>
        <col width='15%'/>
        <col width='*%'/>
      </colgroup>
      <tbdoy>
        <tr>
          <td>Writer</td>
          <td><input type="text" name="postswriter" size="20" maxlength="20" value="<%=row.postswriter%>"></td>
        </tr>
        <tr>
          <td>Title</td>
          <td><input type="text" name="poststitle" size="70" maxlength="250" value="<%=row.poststitle%>"></td>
        </tr>
        <tr>
          <td>Memo</td>
          <td><textarea name="postsmemo" rows="5" cols="60"><%=row.postsmemo%></textarea></td>
        </tr>
      </tbdoy>
    </table>
    <a href="#" onclick="form1.submit()">저장</a>
    <input type="hidden" name="postsno" value="<%=row.postsno%>">
    <input type="hidden" name="postsdate" value="<%=row.postsdate%>">
  </form>
</body>
</html>

 

서버를 실행한 후 http://localhost:3000/rPosts/List 에 접속하여 [New] 버튼을 눌러 새로운 글을 작성한다.

 

 

글을 [저장] 을 할 경우 Firebase Realtime Database 에 posts 이 새로 생기며 안에 새로운 데이터가 입력된다.

 

Firebase Realtime Database 단점

1. 내림차순(DESC) 정렬 안됨

2. 데이터 수정 시 모든 필드를 나열해야 함

3. 검색 기능도 제한적이다.

 

참고

https://forest71.tistory.com/166

 


Cloud Firestore 사용

Cloud Firestore

 

Cloud Firestore  |  Firebase

유연하고 확장 가능한 NoSQL 클라우드 데이터베이스를 사용해 클라이언트 및 서버 측 개발에 사용되는 데이터를 저장하고 동기화하세요.

firebase.google.com

Colud Firestore 설정

1. Cloud Firestore 의 [규칙] 탭에서 규칙을 수정한다. (Ex. allow read, write: if false -> allow read, write: if request.auth.uid != null;)

규칙에 대한 설명

 

Cloud Firestore 사용법

app.js

const cpostsRouter = require('./routes/cPosts');

app.use('/cPosts', cpostsRouter);

// false 를 true 로 수정
app.use(express.urlencoded({ extended: true }));

 

routes/cPosts.js

var express = require('express');
var router = express.Router();

const admin = require('firebase-admin');

// firebase Admin 초기화
const firebaseAdmin = admin.initializeApp({
  credential: admin.credential.cert({
      "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": 
    }),
  databaseURL: ,
  storageBucket: 
}, "cposts");

const dateFormat = require('dateformat');

///
/// 데이터 베이스 관련
///

router.get('/List', function(req, res, next) {
  firebaseAdmin.firestore().collection('posts').orderBy("postsdate", "desc").get()
  .then((snapshot) => {
    var rows = [];

    snapshot.forEach((element) => {
      var childData = element.data();

      childData.postsdate = dateFormat(childData.postsdate, "yyyy-mm-dd");
      rows.push(childData);
    });
    
    res.render('cPosts/List', {rows:rows});
    return;
  }).catch((err) => {
    console.log(err);
  });
});

router.get('/Read', function(req, res, next) {
  firebaseAdmin.firestore().collection('posts').doc(req.query.postsno).get()
  .then((snapshot) => {
    var childData = snapshot.data();

    res.render('cPosts/Read', {row:childData});
    return;
  }).catch((err) => {
    console.log(err);
  });
});

router.get('/Write', function(req, res, next) {
  if(!req.query.postsno) {
    res.render('cPosts/Write', {row:""});
    return;
  }

  firebaseAdmin.firestore().collection('posts').doc(req.body.postsno).get()
  .then((snapshot) => {
    var childData = snapshot.data();

    res.render('cPosts/Write', {row:childData});
    return;
  }).catch((err) => {
    console.log(err);
  });
});

router.post('/Save', function(req, res, next) {
  var postData = req.body;

  if (!postData.postsno) 
  {
	postData.postsdate = Date.now();
	doc = firebaseAdmin.firestore().collection('posts').doc();
    postData.postsno = doc.id;
	doc.set(postData);
  } 
  else {
	doc = firebaseAdmin.firestore().collection('posts').doc(postData.postsno);
    doc.update(postData);
  }

  res.redirect('List');
  return;
});

router.get('/Delete', function(req, res, next) { 
  firebaseAdmin.firestore().collection('posts').doc(req.query.postsno).delete();

  res.redirect('List');
  return;
});

module.exports = router;
// 'posts' 컬렉션의 전체 데이터를 'postsdate'을 기준으로 내림차순 정렬 한 후 가지고 온다.
firebaseAdmin.firestore().collection('posts').orderBy("postsdate", "desc").get()

// 'posts' 컬렉션에서 특정 key 값(req.query.postsno) 를 가진 데이터를 가지고 온다.
firebaseAdmin.firestore().collection('posts').doc(req.query.postsno).get()

// 'posts' 컬렉션에서 새로운 key 값을 생성 후
var doc = firebaseAdmin.firestore().collection('posts').doc();
postData.postsno = doc.id;
// 새로운 데이터를 넣는다.
doc.set(postData);

// 'posts' 컬렉션에서 기존 key 값(postData.postsno)의 데이터를
doc = firebaseAdmin.firestore().collection('posts').doc(postData.postsno);
// 수정한다.
doc.update(postData);

 

서버를 실행한 후 http://localhost:3000/cPosts/List 에 접속하여 [New] 버튼을 눌러 새로운 글을 작성한다.

 

 

'posts' 라는 새로운 컬렉션이 생기고 새로운 key 값을 가진 데이터가 저장이 된다.

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기