본문 바로가기
Programming/JavaScript

firestore & storage 사용하기

by NAMP 2018. 4. 20.

firestore & storage 사용하기

 

firestore 에는 문서를 저장하고, storage 에는 파일을 저장합니다. firestore에 파일도 저장할 수 있지만 2MiB 제한이 있습니다.

firstore 저장소 사용하기

데이터베이스 선택: Cloud Firestore 또는 실시간 데이터베이스

프로젝트 생성

firebase console에서 새 프로젝트를 생성합니다.

웹 앱에 Firebase 추가를 눌러서 config 정보를 확인할 수 있습니다.

firebase 설치

yarn 으로 설치하였습니다.

$ yarn add firebase

파일 추가

프로젝트에서 firebase를 사용하기 위한 파일들을 추가합니다.

위에서 얻은 정보를 입력합니다. apiKey 등등.

// firebaseConfig.js
export defaut {
    apiKey: "AIzaSyA3HtpUV_6UNwFmdaxpSFpUPpJmTJsvpSY",
    authDomain: "sweltering-95126.firebaseapp.com",
    databaseURL: "https://sweltering-9516.firebaseio.com",
    projectId: "sweltering-9516",
    storageBucket: "sweltering-9516.appspot.com",
    messagingSenderId: "773479174081"
}
// firebaseInit.js
import firebase from "firebase";
import "firebase/firestore";
import firebaeConfig from "./firebaseConfig";

if (!firebase.apps.length) {
  firebase.initializeApp(firebaeConfig);
}

export default firebase.firestore();

firestore 사용하기

// data.js
import db from "lib/firebaseInit";

사용하는 법은 이곳 에서 확인할 수 있습니다.

컬렉션 가져오기

const SOURCE = 'vworld';
const layer = 'facility_build';
const level = '15'

const levelRef = db
  .collection(SOURCE)
  .doc(layer)
  .collection(level);
  
levelRef.get().then((docs)=>{  
  docs.forEach(doc => {
    const data = doc.data();
    const key = JSON.stringify({ idx: data.idx, idy: data.idy });
    console.log(key);
  });
});

가장오른쪽에 있는 문서들의 내용이 콘솔로 출력됩니다.

문서 가져오기

const docRef = db
  .collection(SOURCE)
  .doc(layer)
  .collection(level.toString())
  .doc(`${idx}_${idy}`);

try {
  const doc = await docRef.get();
  const data = doc.data();
  console.log("GetLayer from FireStore", data);
  return data;
} catch (e) {
  console.log("Error reading document:", e);
}

문서 id를 바탕으로 문서를 바로 가져올 수 있습니다.

필터링

where를 사용하여 필터링 합니다.

Cloud Firestore로 데이터 정렬 및 제한  |  Firebase

간단한 쿼리

var citiesRef = db.collection("cities");
var query = citiesRef.where("capital", "==", true);
citiesRef.where("state", "==", "CA")
citiesRef.where("population", "<", 100000)
citiesRef.where("name", ">=", "San Francisco")

복합 쿼리

citiesRef.where("state", "==", "CO").where("name", "==", "Denver")
citiesRef.where("state", "==", "CA").where("population", "<", 1000000)
citiesRef.where("state", ">=", "CA").where("state", "<=", "IN")
citiesRef.where("state", "==", "CA").where("population", ">", 1000000)

잘못된 방법: 서로 다른 필드에 범위 필터 사용

citiesRef.where("state", ">=", "CA").where("population", ">", 100000)

서로 다른 필드에 범위 적용

적당한 방법을 찾지 못하여, 서로 다른 조건의 쿼리를 모두 호출하여 모두 가지고 있는 경우로 처리하였습니다.

const levelRef = db
  .collection(SOURCE)
  .doc(layer)
  .collection(level);
const queryX = levelRef.where(CENTER_POS_X, ">=", min_lon).where(CENTER_POS_X, "<=", max_lon);
const queryY = levelRef.where(CENTER_POS_Y, ">=", min_lat).where(CENTER_POS_Y, "<=", max_lat);

return Promise.all([queryX.get(), queryY.get()]).then(res => {
  let nodeCountMap = {};
  res.forEach(docs => {
    docs.forEach(doc => {
      const data = doc.data();
      const key = JSON.stringify({ idx: data.idx, idy: data.idy });
      if (nodeCountMap.hasOwnProperty(key)) {
        nodeCountMap[key] = nodeCountMap[key] + 1;
      } else {
        nodeCountMap[key] = 1;
      }
    });
  });

  let nodes = [];
  const resCount = res.length;
  for (const node in nodeCountMap) {
    const count = nodeCountMap[node];
    if (count === resCount) {
      const obj = JSON.parse(node);
      nodes.push(obj);
    }
  }

  return nodes;
});

정렬 제한

citiesRef.orderBy("name").limit(3)
citiesRef.orderBy("name", "desc").limit(3)
citiesRef.orderBy("state").orderBy("population", "desc")
citiesRef.where("population", ">", 100000).orderBy("population").limit(2)

잘못된 방법: 서로 다른 필드에 범위 필터 및 1차 orderBy 사용

citiesRef.where("population", ">", 100000).orderBy("country")

문서 저장

const docRef = db
  .collection(SOURCE)
  .doc(layer)
  .collection(level.toString())
  .doc(`${idx}_${idy}`);

const data = {
  idx, 
  idy,
  ...,
}

docRef
  .set(
    {
      data,
    },
    { merge: true },
  )
  .then(() => console.log("Document successfully written!:", data))
  .catch(error => console.error("Error writing document: ", error));

set()을 호출하여 문서를 저장합니다. 하위 경로의 컬렉션, 문서가 없는 경우는 자동으로 생성됩니다.

firestorage 저장소 사용하기

파일 수정

// firebaseInit.js
import firebase from "firebase";
import "firebase/firestore";
import "firebase/storage";
import firebaeConfig from "./firebaseConfig";

if (!firebase.apps.length) {
  firebase.initializeApp(firebaeConfig);
}

export const storageRef = firebase.storage().ref();
export const db = firebase.firestore();

firebase.storage().ref()를 추가합니다.

// data.js
import { db, storageRef } from "lib/firebaseInit";

db → firestore 사용을 위한 객체

storageRef → storage 사용을 위한 객체

cors 설정하기

  1. gsutil 을 설치합니다.
  2. cors.json 파일을 생성합니다.
  3. gsutil을 실행하여하여 CORS 설정을 합니다.
//cors.json
[
  {
    "origin": [
      "*"
    ],
    "method": [
      "GET"
    ],
    "maxAgeSeconds": 3600
  }
]
$ gsutil cors set cors.json gs://my-bucket

storage 저장하기

// data.js
const filePath = `${SOURCE}/${layer}/${level}/${idx}/${idy}/${filename}`;
const fileRef = storageRef.child(filePath);

fileRef
  .put(layerInfo.data)
  .then(function(snapshot) {
    console.log("Uploaded a blob or layerInfo!", filePath, snapshot);
  })
  .catch(function(err) {
    console.log(err);
  });

put()으로 파일을 입력합니다.

storage 가져오기

const filePath = `${SOURCE}/${layer}/${level}/${idx}/${idy}/${filename}`;
const fileRef = storageRef.child(filePath);

try {
  const url = await fileRef.getDownloadURL();
  const result = await axios.get(url, {
    responseType: "arraybuffer",
  });
  return result.data;
} catch (e) {
  console.log("[ERROR] {data.js:getFile} ", e);
}

getDownloadURL 을 통해서 URL을 얻습니다. 이 URL을 통해서 파일을 다운로드 받습니다.

CORS 설정이 되어 있어야 파일을 받을 수 있습니다.

참고

tags: cloud, firestore, storage, javascript, web, js

댓글