Firebase - Firebase CRUD 구현

Jinsung·2021년 9월 28일
5
post-thumbnail

들어가며

firebase는 서버(backend)의 역할을 대신 수행해주어 serverless를 가능하게 해주는 유용한 application입니다. 그런 firebase에 crud를 수행하기위해 어떤 api를 요청해야 하는지를 다뤄보겠습니다.

1. 🔥FireStore에 데이터 추가하기

🎯add()

문서에 유의미한 ID를 두지 않고 Cloud Firestore에서 자동으로 ID를 생성하도록 하는 것이 편리할 수도 있습니다. 아래와 같은 방식으로 add()를 호출합니다.

// firebase api 문서의 예제 코드
// Add a new document with a generated id.
db.collection("cities").add({
    name: "Tokyo",
    country: "Japan"
})
.then((docRef) => {
    console.log("Document written with ID: ", docRef.id);
})
.catch((error) => {
    console.error("Error adding document: ", error);
});

📚예시 코드

const onSubmit = async (e) => {
  e.preventDefault();
  await dbService.collection('messages').add({
    text: message,
    createdAt: Date.now(),
    creatorId: userObj.uid, // userObj: props로 넘겨준 login한 user 정보
  });
  setMessage('');
};

2. 🔥FireStore 실시간 업데이트 가져오기

🎯1) onSnapshot()

문서를 수신 대기할 수 있는 방법으로 사용자가 제공하는 callback이 최초 호출 시 단일 문서의 현재 콘텐츠로 문서 스냅샷이 즉시 생성됩니다. 콘텐츠가 변경될 때마다 callback이 호출되어 문서 스냅샷을 업데이트 합니다.

// firebase api 문서의 예제 코드
db.collection("cities").doc("SF")
    .onSnapshot((doc) => {
        console.log("Current data: ", doc.data());
    });

🎯2) orderBy()

쿼리 조회시 default로 문서 ID에 따라 오름차순으로 검색합니다. orderBy()를 사옹하면 데이터의 정렬 순서를 지정하고 limit()를 사용하여 검색된 문서 수를 제한할 수 있습니다.

// firebase api 문서의 예제 코드
citiesRef.orderBy("name").limit(3);

📚예시 코드

useEffect(() => {
  dbService // dbService = firebase.firestore();
    .collection('messages')
    .orderBy('createdAt', 'desc') // 생성일(createdAt) 역순으로 order
    .onSnapshot((snapshot) => {
      const messageArray = snapshot.docs.map((doc) => ({
        id: doc.id,
        ...doc.data(),
      }));
      setMessages(messageArray);
    });
}, []);

3. 🔥FireStore 데이터 업데이트

🎯update()

문서의 일부 필드를 업데이트를 하기위해 update() 메서드를 사용합니다.

// firebase api 문서의 예제 코드
var washingtonRef = db.collection("cities").doc("DC");

// Set the "capital" field of the city 'DC'
return washingtonRef.update({
    capital: true
})
.then(() => {
    console.log("Document successfully updated!");
})
.catch((error) => {
    // The document probably doesn't exist.
    console.error("Error updating document: ", error);
});

📚예시 코드

// 작성 코드
const [isEditing, setIsEditing] = useState(false);
const [newMessage, setNewMessage] = useState(messageObj.text);

const toggleIsEditing = () => setIsEditing((prev) => !prev);

const onEditChange = (e) => {
  const { value } = e.target;
  setNewMessage(value);
};

const onEditMessageSubmit = async (e) => {
  e.preventDefault();
  await dbService.doc(`messages/${messageObj.id}`).update({
    text: newMessage,
  });
  setIsEditing(false);
};

4. 🔥FireStore 데이터 삭제

🎯delete()

문서를 삭제하기위해 delete() 메서드를 사용합니다.

// firebase api 문서의 예제 코드
db.collection("cities").doc("DC").delete().then(() => {
    console.log("Document successfully deleted!");
}).catch((error) => {
    console.error("Error removing document: ", error);
});

📚예시 코드

// 작성 코드
const [isEditing, setIsEditing] = useState(false);
const [newMessage, setNewMessage] = useState(messageObj.text);

const toggleIsEditing = () => setIsEditing((prev) => !prev);

const onEditChange = (e) => {
  const { value } = e.target;
  setNewMessage(value);
};

const onDeleteClick = async () => {
  const ok = window.confirm('메세지를 삭제하시겠습니까?');
  if (ok) {
    await dbService.collection('messages').doc(`${messageObj.id}`).delete();
  }
};

5. 🔥FireStore 데이터 쿼리 및 필터링

Firestore 에는 컬렉션, 컬렉션 그룹에서 검색할 문서를 지정할 수 있는 강력한 쿼리 기능을 제공하고 있습니다. ex) get(), addSnapshotListener()
쿼리객체를 만든 후 get()함수를 사용하여 결과를 검색합니다.
where() 메서드는 필터링할 필드, 비교 연산자, 의 3가지 매개변수를 사용합니다.

// firebase api 문서의 예제 코드
db.collection("cities").where("capital", "==", true)
    .get()
    .then((querySnapshot) => {
        querySnapshot.forEach((doc) => {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch((error) => {
        console.log("Error getting documents: ", error);
    });

📚예시 코드

  const getMyMessages = async () => {
    await dbService
      .collection('messages')
      .where('creatorId', '==', userObj.uid)
      .orderBy('createdAt')
      .get();
  };

6. 🔥FireStore 파일[업로드, 다운로드]

🎯 1) 파일 업로드

Cloud Sotrage에 파일을 업로드하기위해 먼저 파일 이름, 파일 전체경로를 가르키는 참조를 만듭니다.

// firebase api 문서의 예제 코드
// Create a root reference
var storageRef = firebase.storage().ref();

// Create a reference to 'images/mountains.jpg'
var mountainImagesRef = storageRef.child('images/mountains.jpg');

Blob, File 또는 Unit8Array를 사용할 수 없으면 putString()메서드를 사용하여 원시 문자열, base64, base64url 또는 data_url로 인코딩된 문자열을 Cloud Sotrage에 추가할 수 있습니다.

// firebase api 문서의 예제 코드
// Raw string is the default if no format is provided
var message = 'This is my message.';
ref.putString(message).then(function(snapshot) {
  console.log('Uploaded a raw string!');
});

// Data URL string
var message = 'data:text/plain;base64,5b6p5Y+344GX44G+44blahblah';
ref.putString(message, 'data_url').then(function(snapshot) {
  console.log('Uploaded a data_url string!');
});

🎯 2) URL을 통한 데이터 다운로드

스토리지 참조에 대하여 getDonwloadURL() 메서드를 호출하여 파일의 다운로드 URL을 가져옵니다.

// firebase api 문서의 예제 코드
// Create a reference to the file we want to download
var starsRef = storageRef.child('images/stars.jpg');
// Get the download URL
starsRef.getDownloadURL().then(function(url) {
  // Insert url into an <img> tag to "download"
}).catch(function(error) {
	...
  }
});

📚예시 코드

const [attachment, setAttachment] = useState('');

const onFileChange = (e) => {
  const { files } = e.target;
  const theFile = files[0];
  // FileReader의 Instance 생성
  const reader = new FileReader();
  // eventListener
  reader.onloadend = (e) => {
    const { result } = e.currentTarget;
    // attachment state를 data_url형식의 string값으로 업데이트
    setAttachment(result);
  };
  reader.readAsDataURL(theFile);
};

const onSubmit = async (e) => {
  e.preventDefault();
  let attachmentUrl = '';
  // 사진 첨부를 안할 수도 있기 때문에 조건문
  if (attachment !== '') {
    // uuid library 사용
    const fileRef = storageService.ref().child(`${userObj.uid}/${uuidv4()}`);
    // putString method로 file 업로드
    const response = await fileRef.putString(attachment, 'data_url');
    // getDownloadURL method로 file 다운로드
    attachmentUrl = await response.ref.getDownloadURL();
  }
  const messageObj = {
    text: message,
    createdAt: Date.now(),
    creatorId: userObj.uid,
    attachmentUrl,
  };
  await dbService.collection('messages').add(messageObj);
  setMessage('');
  setAttachment('');
};

7. 🔥FireStore 파일삭제

파일을 삭제하기위해 파일을 가르키는 참조(reference doc link)를 먼저 만듭니다. delete()를 사용하여 파일을 삭제하며 정상적으로 처리 되었을 경우 Promise가 반환됩니다.

  • refFromURL - Returns a reference for the given absolute URL.
  • refFromURL (url : string) - Reference
// firebase api 문서의 예제 코드
// Create a reference to the file to delete
var desertRef = storageRef.child('images/desert.jpg');

// Delete the file
desertRef.delete().then(function() {
  // File deleted successfully
}).catch(function(error) {
  // Uh-oh, an error occurred!
});

📚예시 코드

const onDeleteClick = async () => {
  const imgUrl = messageObj.attachmentUrl;
  const ok = window.confirm('메세지를 삭제하시겠습니까?');
  if (ok) {
    newMessage &&
      (await dbService
        .collection('messages')
        .doc(`${messageObj.id}`)
        .delete());
    imgUrl &&
      (await storageService.refFromURL(messageObj.attachmentUrl).delete());
  }
};

마무리

firebase 미니 프로젝트를 만들기 전에 여러가지 기능들에 대하여 정리해 보았습니다. 개인적인 생각으로 아직까진 serverLess로서 완벽하게 구현이 가능하진 않겠지만 어느정도 소규모 프로젝트나 crud가 메인인 프로젝트인 경우에는 firebase만으로 충분히 좋은 서비스를 구현 가능할 것 같습니다.

0개의 댓글