Glacier's Daily Log

(Flutter) 플러터 Firestore 연동 및 데이터 불러와서 List 자료형과 Map 자료형에 알맞게 넣기 본문

Coding/Flutter

(Flutter) 플러터 Firestore 연동 및 데이터 불러와서 List 자료형과 Map 자료형에 알맞게 넣기

h__glacier_ 2022. 9. 13. 01:20
반응형

진행중인 토이프로젝트

나는 언어를 새로 배울 때 강의만 듣고 배우는 것을 제일 싫어한다.

지겹고 재미 없을 뿐만 아니라, 왜 배워야하는지도 이해하지 못하고 주입식으로 넣으면 효율성이 매우 떨어진다.

 

그래서 항상 기본적인 문법만 공부하고 토이프로젝트를 만들어보며 직접 부딪혀본다.

사람마다 편차가 있겠지만, 나는 이렇게 공부하는게 효율이 엄청 좋고 실력도 굉장히 빨리 는다고 생각한다.

왜나하면, 직접 프로젝트를 만들어보다 보면 주입식으로 배울때는 왜 배워야하는지 몰랐던 것들이

실제로 필요해지기 때문에 직접 사용해보며 체득하기 때문이다.


이번 플러터 공부는 포트폴리오 앱을 시작으로 토이프로젝트를 시작하였다.

포트폴리오앱이 완료된 후, Firebase 연동을 배우기 위해 "MBTI 빅데이터" 라는 프로젝트를 시작해보았다.

 

Firebase와 연동하여, 사용자가 자신의 MBTI를 입력하면

전체 사용자 중 자신의 MBTI가 몇 %를 차지하며, 추후에는 더 많은 정보를 입력시켜서

MBTI에 대한 다양한 통계를 보여주는 프로젝트이다.

 

UI를 이쁘게 만들어보려고 다양한 예제들을 참고했지만, 저정도가 우선 지금 실력에서는 최선인 것 같고

FireStore과의 연동도 성공했다.

 

우선 메인화면에서 사용자 한명한명이 엠비티아이를 입력하면

서버에는 위와 같이 입력이 된다.


내가 원하는 것은, 이렇게 입력된 데이터들을

다음 페이지에서 한번에 불러와서

총 16가지의 MBTI들과 해당되는 횟수를 Key-Value 쌍으로 저장하는 것이다.

 

이를 수행하기 위해 파이썬의 딕셔너리 자료형과 비슷한 자료형을 찾아보니

플러터에는 자바와 같이 Map 자료형을 사용하고 있다.

 

Map resultMap = {
    'ISFJ' : 0,'ISFP' : 0,'ISTJ' : 0,'ISTP' : 0,'INFJ' : 0,'INFP' : 0,'INTJ' : 0,'INTP' : 0,
    'ESFJ' : 0,'ESFP' : 0,'ESTJ' : 0,'ESTP' : 0,'ENFJ' : 0,'ENFP' : 0,'ENTJ' : 0,'ENTP' : 0,
  };

따라서 이렇게 총 16개의 엠비티아이를 Key로, Value는 0으로 초기화시켜주었다.


이제 해야할 일은, Firestore에 저장되어있는 정보를 모두 불러와서 getter-setter로

각 이용자의 mbti만 빼온 다음,

미리 만들어둔 자료형에서 해당하는 MBTI의 Value만 ++ 해주는 것이다.

 

우선 그렇게 하려면 FireStore에 있는 정보를 가져오는 코드부터 작성해야한다.

 

Future<Map> getMbtiModels() async {
  //FireStore 컬렉션 중 "users" 에 있는 모든 데이터를 긁어오는 코드
  CollectionReference<Map<String, dynamic>> collectionReference =
  FirebaseFirestore.instance.collection("users");
  QuerySnapshot<Map<String, dynamic>> querySnapshot =
  await collectionReference.get();

  // 원하는 값을 저장하기 위한 Map자료형
  Map resultMap = {
    'ISFJ' : 0,'ISFP' : 0,'ISTJ' : 0,'ISTP' : 0,'INFJ' : 0,'INFP' : 0,'INTJ' : 0,'INTP' : 0,
    'ESFJ' : 0,'ESFP' : 0,'ESTJ' : 0,'ESTP' : 0,'ENFJ' : 0,'ENFP' : 0,'ENTJ' : 0,'ENTP' : 0,
  };

  // FireStore에서 가져온 객체를 저장하기 위한 리스트 선언
  List<mbtiModel> res = [];
  
  // FireStore에서 가져온 전체 데이터를, 각각 미리 만들어놓은 model로 파싱한다음 리스트에 하나씩 넣는다.
  for (var doc in querySnapshot.docs) {
    mbtiModel fireModel = mbtiModel.fromQuerySnapshot(doc);
    res.add(fireModel);
  }
  
  // data가 잘 가져와졌는지 for문으로 하나씩 뽑아서 print해봄
  for(int i=0; i<res.length; i++){
    print(res[i].toString());
  }
  return resultMap;
}

구글링과 내 수정으로 탄생한 getMbtiModels() 함수.

오늘 독학한 얕은 지식으로 감히 주석을 달아보았다....

고수님이 보시면 검토 한번 부탁드립니다 :)

 

우선 반환형의 Future<>는 뭔가 하니, 비동기 처리이기 때문에

원하는 값이 바로 return 되지 않는다.

불러오는 시간이 지난 후, error가 나올지 원하는 값이 return될지 모르는 것이기 때문에반환형에 Future를 감싸준다.

이렇게 Future로 감싸진 반환형은 추후에 사용할 때 FutureBuilder 라는 기능을 사용해 뽑아올 수 있다.

 

일단 이 코드까지는 res라는 리스트에 모든 객체가 담겨있는 부분까지만 작성이 되었다.

여기서 객체란,

이렇게 사용자 하나하나를 뜻하는데, 이 객체를 따로 관리하기위해 mbtiModel 이라는 클래스를 만들었다.

import 'dart:ffi';
import 'package:cloud_firestore/cloud_firestore.dart';

class mbtiModel {

  mbtiModel({
    this.mbti,
    this.uid,
    this.joinedTime,
  });

  String? mbti;
  String? uid;
  int? joinedTime;
  DocumentReference? reference;

  mbtiModel.fromJson(dynamic json,this.reference) {
    mbti = json['mbti'];
    uid = json['uid'];
    joinedTime = json['joinedTime'];
  }


  mbtiModel.fromSnapShot(DocumentSnapshot<Map<String, dynamic>> snapshot)
      : this.fromJson(snapshot.data(),snapshot.reference);

  mbtiModel.fromQuerySnapshot(
      QueryDocumentSnapshot<Map<String, dynamic>> snapshot)
      : this.fromJson(snapshot.data(),snapshot.reference);

  // 저장시에 사용
  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['mbti'] = mbti;
    map['uid'] = uid;
    map['joinedTime'] = joinedTime;
    return map;
  }

  @override
  String toString() {
    return 'mbtiModel{mbti: $mbti, uid: $uid, joinedTime: $joinedTime, reference: $reference}';
  }
}

이렇게 내가 필요한 3개의 변수를 관리하기 위해서 getter/setter 및 toString 등이 있는 모델 클래스를 만들었기 때문에

위의 코드에서 List<mbtiModel> 형의 리스트에 담아서 쉽게 내가 원하는 값을 뽑아낼 수 있게 되는 것이다.


이제 남은 할일은?

뽑아온 List<mbtiModel> res 리스트에서

for문을 돌려서, if(res[i].mbti == "ISFJ") 이렇게 조건문을 건다음

Map 자료형 속 해당하는 MBTI의 value를 1씩 늘려주는 것이다.

 

if문을 사용해도 되겠지만, 노가다 작업이 예상되기 때문에 switch문을 사용하였다.

dart언어는 java와 문법이 거의 유사하여 배우는데 어려움이 크게 없는 것 같다.

 

Future<Map> getMbtiModels() async {
  CollectionReference<Map<String, dynamic>> collectionReference =
  FirebaseFirestore.instance.collection("users");
  QuerySnapshot<Map<String, dynamic>> querySnapshot =
  await collectionReference.get();

  Map resultMap = {
    'ISFJ' : 0,'ISFP' : 0,'ISTJ' : 0,'ISTP' : 0,'INFJ' : 0,'INFP' : 0,'INTJ' : 0,'INTP' : 0,
    'ESFJ' : 0,'ESFP' : 0,'ESTJ' : 0,'ESTP' : 0,'ENFJ' : 0,'ENFP' : 0,'ENTJ' : 0,'ENTP' : 0,
  };

  List<mbtiModel> res = [];
  for (var doc in querySnapshot.docs) {
    mbtiModel fireModel = mbtiModel.fromQuerySnapshot(doc);
    res.add(fireModel);
  }
  for(int i=0; i<res.length; i++){
    print(res[i].toString());
    switch(res[i].mbti){
      case "ISFJ":
        print("");
        resultMap['ISFJ'] += 1;
        break;
      case "ISFP":
        resultMap['ISFP'] += 1;
        print("");
        break;
      case "ISTJ":
        print("");
        resultMap['ISTJ'] += 1;
        break;
      case "ISTP":
        resultMap['ISTP'] += 1;
        print("");
        break;
      case "INFJ":
        resultMap['INFJ'] += 1;
        print("");
        break;
      case "INFP":
        resultMap['INFP'] += 1;
        print("");
        break;
      case "INTJ":
        resultMap['INTJ'] += 1;
        print("");
        break;
      case "INTP":
        resultMap['INTP'] += 1;
        print("");
        break;
      case "ESFJ":
        resultMap['ESFJ'] += 1;
        print("");
        break;
      case "ESFP":
        resultMap['ESFP'] += 1;
        print("");
        break;
      case "ESTJ":
        resultMap['ESTJ'] += 1;
        print("");
        break;
      case "ESTP":
        resultMap['ESTP'] += 1;
        print("");
        break;
      case "ENFJ":
        resultMap['ENFJ'] += 1;
        print("");
        break;
      case "ENFP":
        resultMap['ENFP'] += 1;
        print("");
        break;
      case "ENTJ":
        resultMap['ENTJ'] += 1;
        print("");
        break;
      case "ENTP":
        resultMap['ENTP'] += 1;
        print("");
        break;

    }
  }
  print(resultMap.toString());
  return resultMap;
}

엄청난 switch-case 노가다를 마친 완성된 함수.

 

모든 데이터에서 for문을 돌려서, mbti만 뽑아낸 다음

case문을 활용해서 map자료형 속 해당하는 mbti key의 value를 1씩 늘려주는 것이다.

 

이렇게 해서 Hot Reload를 해보니?

Wow. 내가 원하는대로 되었다!

이제 남은것은 이 데이터를 원형 차트에 plot 하는 것이다.

 

아무래도 비동기 처리이다보니 해당부분을 공부하고 진행해야 할 것 같아서

이번 포스팅은 이까지..!

반응형
Comments