Don't think! Just do it!

종합 IT 기술 정체성 카오스 블로그! 이... 이곳은 어디지?

Flutter/Flutter Project

[소셜차트] 앱 제작기 #13. 좋아요 기능 (Distributed Counter)

방피터 2022. 11. 30. 00:19

하아... 누가 간단한 KiCad 알바 좀 하자고 해서 했는데;;; 2주를 날렸어... ㅠㅠ 화딱지나... 암튼 앱 개발 속행!!

좋아요! 기능은 매우 보편적이지.. 그런데 이게 은근히 짜증나... 우선 누가 좋아요를 눌렀는지 기록해야하고, 그리고 몇개의 좋아요인지도 알아내야 해. 난 firestore를 사용중이니 그걸 기준으로 하자면 단순하게 좋아요를 누른 사람을 기록하는 건 간단해. 그냥 sub collection 하나 만들고 user id를 포함한 문서를 계속 더하거나 빼면 되니까.

좋아요! 구현!

그런데 말이지.... 다른 DB는 모르겠지만 적어도 firestore에서는 좋아요를 카운트하는 일은 간단하지가 않아;; 왜냐하면 firestore에서 허용되는 문서 업데이트 주기가 초당 1회이기 때문이지;; 전세계에서 BTS팬들이 BTS글에다가 좋아요를 누른다고 생각해봐...ㅎㄷㄷ 생각만 해도 끔찍... 당연히 이런 문제를 구글형들도 알고 있어. 그래서 이럴때 쓰라고 Distributed Counter라는 건 제안해 주셨어.👇👇

 

2022.11.28 - [Cloud services/Google Cloud] - [Firestore] Distributed Counter

 

[Firestore] Distributed Counter

허용되는 Firestore 문서 업데이트 주기가 초당 1회야. 초당 1회를 넘어가면 보장을 못한다는 거겠지? 음.. 그러면 "좋아요, 👍, ❤️" 같은 거 구현하려면 망하겠네? 유명한 인플루언서가 올리면 좋

engschool.tistory.com

위 글에서 소개되어 있는데로 난 distributed counter extension을 설치한 상태로 해당 기능을 구현해놨으니까 참고해.

간단하게 extension이 동작하는 방식을 요약하자면 A라는 firestore 문서에다가 "_counter_shards_"라는 subcollection을 만들고 더하거나 빼고 싶은 카운터 이름을 넣어서 문서를 생성하면 A 문서의 카운터에 합산이 된다 이거지. ㅋㅋㅋ 개소리냐고? 그림 ㄱㄱ

그림 보면 알겠지? 아무 문서에다가 _counter_shards_라는 서브 collection 만들고 문서 추가하면 상위 문서의 counter에 합산돼.

이것만 이해하고 있으면 구현은 쏘 이지!👇

  void onLikeButtonPress() {
    if (!likePressed) {//좋아요 버튼이 안눌려있으면
      //likeUserList에다가 현재 userid로 document 추가.
      likeUserListColRef(cardId).doc(firebaseAuth.currentUser!.uid).set(
          ModelUserList(
              userId: firebaseAuth.currentUser!.uid,
              createdAt: Timestamp.now()));
      //_counter_shards_ subcollection에 likeCounter:1 포함하여 문서 추가
      userInsightCardColRef()
          .doc(cardId)
          .collection("_counter_shards_")	
          .add({"likeCounter": 1});
      //화면에 보이는 likeCounter++;
      currentLikeCounter++;
      likePressed = !likePressed;
    } else {// 좋아요 버튼이 눌려 있나?
      //likeUserList에서 현재 user 문서 삭제!
      likeUserListColRef(cardId).doc(firebaseAuth.currentUser!.uid).delete();
      //_counter_shards_ subcollection에 likeCounter:-1 포함하여 문서 추가
      userInsightCardColRef()
          .doc(cardId)
          .collection(SHARD_COLLECTION_ID)
          .add({"likeCounter": -1});
      //화면에 보이는 likeCounter--;
      currentLikeCounter--;
      likePressed = !likePressed;
	}
  }

이렇게 하여 초당 1만회까지 업데이트가 가능한 좋아요 기능 완성!... 완성? 놉 아니지. 위에서처럼 여러가지 firestore 동작을 할 때는 transaction이나 batch를 써야해. 난 transaction을 사용할건데 transaction은 여러가지 동작중에서 어느 한 동작을 실패하면 전체를 되돌리기 때문에 에러 처리가 매우 간단해지지.👇👇

  void onLikeButtonPress() {
    if (!likePressed) {
      likePressed = !likePressed;
      firestore.runTransaction(
        (transaction) async {
          transaction.set(
              likeUserListColRef(cardId).doc(firebaseAuth.currentUser!.uid),
              ModelUserList(
                  userId: firebaseAuth.currentUser!.uid,
                  createdAt: Timestamp.now()));
          transaction.set(
              userInsightCardColRef()
                  .doc(cardId)
                  .collection(SHARD_COLLECTION_ID)
                  .doc(),
              {"likeCounter": 1});
        },
      ).then((value) {
        currentLikeCounter++;
      }, onError: (e) => throw (e));
    } else {
      likePressed = !likePressed;
      firestore.runTransaction(
        (transaction) async {
          transaction.delete(
              likeUserListColRef(cardId).doc(firebaseAuth.currentUser!.uid));
          transaction.set(
              userInsightCardColRef()
                  .doc(cardId)
                  .collection(SHARD_COLLECTION_ID)
                  .doc(),
              {"likeCounter": -1});
        },
      ).then((value) {
        currentLikeCounter--;
      }, onError: (e) => throw (e));
    }
  }

 

Firestore 좋아요 기능 구현(Distributed counter 사용)

벌써 12월이네 ㅠㅠ 빨리 빨리 완성하자! 아자아자!

반응형