본문 바로가기

프론트엔드

Firebase storage 파일 재귀적으로 삭제하기

  • 프로젝트: 공우 어드민
  • 키워드: firebase storage, recursively delete
  • 상황
    1. 하나의 뉴스는 위지윅(WYSIWYG)으로 작성된 텍스트 파일, 썸네일 이미지, 첨부파일을 포함한다.
    2. 위의 3가지 정보(텍스트파일, 이미지, 첨부파일)는 firebase storage에 저장한다.
    3. 뉴스 id가 123 일 경우, 'news/123/content/content.txt', 'news/123/content/contentEng.txt', 'news/123/picture/thumbnail.png', 'news/123/attachments/example_1'...과 같이 저장한다.
    4. 뉴스 목록에서 삭제 버튼을 누르면 DB에 저장된 뉴스 정보와 함께 firebase storage의 파일들도 모두 삭제해야한다.
    5. 하지만 firebase storage API 에서 폴더 삭제(delete folder)를 지원하지 않는다. 

뉴스 목록

  • 해결방법
    1. 특정 폴더 안에 있는 모든 파일을 삭제할 경우, 빈 폴더는 자동 삭제되는 것을 확인했다. 따라서, news/123 이 포함하는 모든 txt, png, docx 등의 파일을 지우면 news/123 폴더는 자동 삭제될 것이다.
    2. deleteFolderContents 라는 함수를 만들고 삭제하고자하는 최상위 폴더를 인자로 넘긴다.
        // firebase storage 데이터 삭제
      deleteFolderContents(`example.com/news/123`);
       
    3. storage 의 listAll API(https://firebase.google.com/docs/storage/web/list-files#list_all_files) 를 사용하여 'news/123' 하위 목록을 얻는다.
        // NOTE: 삭제할 firebase storage directory path 를 받아, listAll 로 파일 목록을 불러온 후 파일을 재귀적으로 삭제.
      export function deleteFolderContents(path: string) {
        const ref = storage.refFromURL(path);
        ref.listAll()
          .then(res => {
            res.items.forEach(fileRef => {
              deleteFile(ref.fullPath, fileRef.name);
            });
            res.prefixes.forEach(folderRef => {
              deleteFolderContents(`gs://${folderRef.bucket}/${folderRef.fullPath}`);
            });
          })
          .catch(() => {
            alert('firebase storage 데이터 나열에 실패했습니다.');
          });
      }

      이때, 각 res는 items 또는 prefixes를 가지는데, items일 경우 해당 객체가 파일임을 의미하고, prefixes면 폴더임을 의미한다.
      items는 파일이므로 deleteFile 함수를 호출하여 파일 삭제를 실행하고, prefixes는 여전히 folder이므로 deleteFolderContents 함수를 재귀 호출한다.
      res 의 구조
    4. items일 경우 파일을 삭제하는 deleteFile 함수를 구현한다.
        export function deleteFile(pathToFile: string, fileName: string) {
        const ref = storage.ref(pathToFile);
        const childRef = ref.child(fileName);
        childRef.delete().then(() => {
          console.log(`firebase storage ${pathToFile}/${fileName} 데이터 삭제 성공`);
        }).catch(() => {
          console.log(`firebase storage ${pathToFile}/${fileName} 데이터 삭제 실패`);
        });
      }​
    5. 이제 삭제 버튼을 누르고 firebase storage 를 확인하면 'news' 폴더 안에 'news/123' 이라는 폴더는 존재하지 않는다!
  • Known issues
    1. 프로젝트에 storage.ref, storage.refFromURL의 사용이 혼재되어있다.