말랑한 하루

[Flutter] Firebase Cloud Firestore 본문

개발/Flutter

[Flutter] Firebase Cloud Firestore

지수는말랑이 2024. 3. 12. 19:54
반응형

기본적으로 Firebase와의 연결과, Firebase.initializeApp을 통해 초기화를 진행해 주어야 한다. 관련 내용은 이전에 작성한 [ Firebase Remote Config ] 글의 "🥕 Flutter에 Firebase 추가" 단락을 참고하여 진행해 주길 바랍니다.

 

※ reference : https://firebase.google.com/docs/firestore/quickstart?hl=ko&_gl=1*30ps05*_up*MQ

🐇 개발 환경 설정

flutter pub add cloud_firestore

 

🥕 앱 체크

※ reference : https://firebase.google.com/docs/app-check?hl=ko&_gl=1*1w5bp70*_up*MQ

🐇 Cloud Firebase 초기화

db = FirebaseFireStore.instance;

아래 내용을 통해 콜렉션 내부 문서의 id값, value값을 가져올 수 있습니다.

// collection 연결
final query = db.collection("collectionName").where(~);

// query 진행
final querySnapshot = await quiery.get();
final docSnapshot = querySnapshot.docs.first

// result 반환
final docId = docSnapshot.id;
final docData = docSnapshot.data();

 

보통 결과 값으로 주어지는 DocumentReference 또는 QuerySnapShot에 포함된 doc을 통해 doc의 id와 data() 정보를 가져올 수 있습니다.

특정 결과의 경우 (단일 항목만 매칭될 수 있도록 Collection 구조를 설계한 경우) 단일 값을 반환하여 위와 같이 사용할 수 있으며, 대부분의 경우 List로 반환되기 때문에 for문을 활용하여 결과 docs에 대한 정보를 얻을 수 있습니다.

🐇 데이터 추가

final user = <String, dynamic>{
	'first': 'Ada',
	'last': 'Lovelace',
	'born': 1915,
}

db.collection('users').add(user).then((DocumentReference doc) =>
	print('DocumentSnapshot added with ID: ${doc.id}));

데이터를 추가할 때는 정형적인 키-값 쌍을 가진 클래스를 사용하는 것을 권장합니다. 키-값 쌍을 자유롭게 사용한다면, 특정 컬렉션 내 문서에 공통되지 않은 키-값 쌍이 생길 수 있음에 유의해야 합니다.

 

add() 메소드 이외에 set() 메소드를 활용하여 추가하는 방법도 있습니다.

 

set() 메소드는 문서가 없으면 생성되며, 문서가 존재한다면 새로 제공한 데이터로 오버라이팅 됩니다. 단, 기존 문서와 병합될 수 있도록 옵션을 지정하는 경우엔 기존 문서에 합쳐집니다.

 

또한, 데이터를 추가할 때 FireStore는 숫자를 항상 배정밀도 부동 소수점으로 저장하므로 사용에 유의해야 합니다.

 

🥕 커스텀 객체

Map 또는 Dictionary객체로는 문서를 표현하기가 불편한 경우가 많으므로 Cloud Firestore는 커스텀 클래스를 사용하여 문서를 작성하는 방식도 지원합니다. Cloud Firestore에서 객체를 지원되는 데이터 유형으로 변환합니다.

class City {
  final String? name;
  final String? state;
  final String? country;
  final bool? capital;
  final int? population;
  final List<String>? regions;

  City({
    this.name,
    this.state,
    this.country,
    this.capital,
    this.population,
    this.regions,
  });

  factory City.fromFirestore(
    DocumentSnapshot<Map<String, dynamic>> snapshot,
    SnapshotOptions? options,
  ) {
    final data = snapshot.data();
    return City(
      name: data?['name'],
      state: data?['state'],
      country: data?['country'],
      capital: data?['capital'],
      population: data?['population'],
      regions:
          data?['regions'] is Iterable ? List.from(data?['regions']) : null,
    );
  }

  Map<String, dynamic> toFirestore() {
    return {
      if (name != null) "name": name,
      if (state != null) "state": state,
      if (country != null) "country": country,
      if (capital != null) "capital": capital,
      if (population != null) "population": population,
      if (regions != null) "regions": regions,
    };
  }
}

// useage
final city = City(
  name: "Los Angeles",
  state: "CA",
  country: "USA",
  capital: false,
  population: 5000000,
  regions: ["west_coast", "socal"],
);
final docRef = db
    .collection("cities")
    .withConverter(
      fromFirestore: City.fromFirestore,
      toFirestore: (City city, options) => city.toFirestore(),
    )
    .doc("LA");
await docRef.set(city);

🐇 데이터 읽기

await db.collection('user').get().then((event) {
	for (var doc in event.docs) {
		print('${doc.id} -> ${doc.data()}');
	}
});

🐇 데이터 업데이트

하위 사용된 doc() 메소드의 경우 내부 요소로 String type의 docId를 필요로 합니다

final washingtonRef = db.collection("cites").doc("DC");
washingtonRef.update({"capital": true}).then(
    (value) => print("DocumentSnapshot successfully updated!"),
    onError: (e) => print("Error updating document $e"));
    
db.collection("users")
	.doc("frank")
	.update({"age": 13, "favorites.color": "Red"});

🐇 데이터 쿼리

final citiesRef = db.collection("cities");

final query = citiesRef.where("state", isEqualTo: "CA");
query.get().then(
	(querySnapshot) {
		print("Success");
		for (var docSnapshot in querySnapshot.docs) {
			print('${docSnapshot.id} => ${docSnapshot.data()}');
		}
	}
	onError: (e) => print(e);
)

final capitalcities = db.collection("cities").where("capital", isEqualTo: true);

🐇 오류

Local module descriptor class for com.google.android.gms.providerinstaller.dynamite not found.

🍒 1

AndroidManifest.xml에 다음 uses-permission tag 추가

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 

 

🍒 2

flutter clean
flutter pub get

 

🍒 3

android emulator의 추가 기능 중, 데이터를 삭제해주는 Wipe Data 실행

 

🍒 4

emulator의 google play services version 상태 확인

정보가 없거나 Loading 중이라면, Update를 진행하여 존재 여부 확인

필자의 경우 Google play services 사용자 추가 및 설치가 완료되었을 때 Firestore 관련 오류가 해결했습니다.

반응형
Comments