이번 글에서는 클라우드 DB인 Firestore에서 최신 데이터를 받아 와서 앱 내부의 DB파일에 저장하는 과정에 대해 설명한다.
앞의 '자동화'에서 최신 영화 데이터를 Firestore에 저장하는 작업을 하루에 한 번씩 한다고 했었다.
여기서 최신 영화 데이터에 대한 의미를 짚고 넘어가야 하는데, 예를 들어 10일에 저장하는 작업을 한다고 치면 최신 영화 데이터는 10일에 나온 영화 데이터가 아닌 3일에 나온 영화데이터를 말한다.
왜 이렇게 정했냐 하면, 등록 분류 일자가 10일이라고 해서 API 및 ors웹 사이트에 10일에 등록된다는 보장이 없기 때문이다.
실제로 영화 데이터들은 보통 등록 분류 일자 기준 1~2일 후에 올라왔었고, 많이 밀린다 하면 3~4일까지도 밀렸었다.
(최대로 밀린 경우는 6일이었는데 이건 추석 + 주말 + 임시공휴일 + 개천절이라는 기막힌 연휴라 그랬던 것..)
이렇게 되면 데이터를 호출해도 값이 오지 않아 Firestore이 텅텅 비어버린다.
따라서 최신 영화 데이터는 당일 기준 7일 전 영화 데이터라고 정했다.
- 10일에 3일에 등록된 영화데이터 Firestore에 저장
- 11일에 4일에 등록된 영화데이터 Firestore에 저장
- 12일에 5일에 등록된 영화데이터 Firestore에 저장
- ..... 이런 식으로
업데이트 과정
앱에서의 DB파일 업데이트 과정은 다음과 같다.
- 최근 업데이트 날짜를 가져온다 (마지막으로 업데이트 한 날짜)
- 최신 업데이트 날짜를 가져온다 (당일 기준 7일 전 날짜)
- 최근 업데이트 날짜부터 최신 업데이트 날짜까지의 영화 데이터를 Firestore에서 가져온다.
- 가져온 영화 데이터를 앱 내부 DB에 저장한다.
- 최근 업데이트 날짜를 갱신한다.
- 끝
1. 최근 업데이트 날짜를 가져온다.
최근 업데이트 날짜는 앱을 종료해도 값이 유지되어야 한다.
따라서 shared_preferences 패키지를 사용하여 최근 업데이트 날짜를 관리한다.
(아래의 패키지는 앱을 종료해도 유지되어야 하는 정보들을 관리할 때 사용하는 패키지다.)
https://pub.dev/packages/shared_preferences
앱의 초기 데이터에는 2023/09/30까지의 영화 데이터가 들어있다.
따라서 앱 처음 실행 시, 최근 업데이트 날짜는 2023/09/30이 된다.
(이 부분은 나중에 initial value setting 설명에 다시 언급할 예정)
최근 업데이트 날짜를 가져오는 함수
/// 최근 업데이트 년/월/일을 가져옴
Future<DateTime> getLastUpdatedDate() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
int? year = prefs.getInt('updatedYear');
int? month = prefs.getInt('updatedMonth');
int? day = prefs.getInt('updatedDay');
return DateTime(year!, month!, day!);
}
2. 최신 업데이트 날짜를 가져온다.
이건 매우 쉽다. 그냥 현재 날짜에서 7일 빼면 되니..
함수 위에 주석에서 설명했지만, 업데이트 시간이 23시라서 편의상 8일 전 데이터를 최신 데이터로 간주한다.
/// Firebase의 가장 최근 업데이트 날짜를 계산
/// 당일 기준 7일 전 데이터가 가장 최신 데이터이지만, 23시에 업데이트하므로 편의상 8일전 데이터를 최신 데이터로 간주함
DateTime getUpdateDate() {
DateTime now = DateTime.now();
DateTime updateDate = DateTime(now.year, now.month, now.day - 8);
return updateDate;
}
3. 최근 업데이트 날짜부터 최신 업데이트 날짜까지의 영화 데이터를 Firestore에서 가져온다.
우선 Dart&Flutter에서 Firestore를 사용하기 위해서는 cloud_firestore 패키지가 필요하다.
https://pub.dev/packages/cloud_firestore
cloud_firestore의 사용법은 위의 Example를 봐도 좋고, 아래의 링크의 usage를 한 번 쭉 읽어봐도 좋다.
https://firebase.flutter.dev/docs/firestore/usage/
날짜를 인자로 받아 그 날짜에 해당하는 영화 데이터를 가져오는 함수이다.
(컬렉션 ID는 '20231010'과 같은 포맷으로 되어 있음)
/// Firestore에서 영화 데이터들을 가져옴
///
/// DateTime 값을 인자로 받고, 년+월+일(ex 20230930)에 해당하는 컬렉션에서 영화정보들을 가져옴
Future<List<Movie>> getMovieFromFirestore(
FirebaseFirestore firestore, DateTime date) async {
List<Movie> movies = [];
final moviesRef = firestore
.collection('${date.year}${date.month.toString().padLeft(2, '0')}${date.day.toString().padLeft(2, '0')}')
.withConverter<Movie>(
fromFirestore: (snapshot, _) => Movie.fromJson(snapshot.data()!),
toFirestore: (movie, _) => movie.toJson(), //do not use
);
await moviesRef.get().then((snapshot) {
for (var doc in (snapshot.docs)) {
movies.add(doc.data());
}
});
return movies;
}
4. 가져온 영화 데이터를 앱 내부 DB에 저장한다.
위의 함수들을 사용하여 최근 업데이트 날짜부터 최신 업데이트 날짜까지의 Firestore 영화 데이터를 가져와 앱 내부 DB에 저장하는 함수이다.
/// 영화정보들을 내부 db에 저장
Future<int> updateMovieInfo() async {
List<Future<List<Movie>>> futures = [];
int movieCount = 0;
DateTime lastUpdatedDate = await getLastUpdatedDate(); // year, month, day
DateTime updateDate = getUpdateDate();
FirebaseFirestore firestore = FirebaseFirestore.instance;
// now.compareTo(future); // -1
// now.compareTo(past); // 1
// now.compareTo(now); // 0
while (true) {
lastUpdatedDate = DateTime(lastUpdatedDate.year, lastUpdatedDate.month, lastUpdatedDate.day + 1);
if (updateDate.compareTo(lastUpdatedDate) < 0) {
break;
}
futures.add(getMovieFromFirestore(firestore, lastUpdatedDate));
}
List<List<Movie>> movieList = await Future.wait(futures);
MovieDatabase db = MovieDatabase();
await db.openDB();
for (List<Movie> movies in movieList) {
movieCount += movies.length;
for (Movie movie in movies) {
db.insertMovie(movie);
}
}
await setLastUpdatedDate(updateDate.year, updateDate.month, updateDate.day);
return movieCount;
}
5. 최근 업데이트 날짜를 갱신한다.
아래의 함수를 사용해서 최근 업데이트 날짜를 갱신한다.
/// 업데이트 후 년/월/일을 저장
Future<void> setLastUpdatedDate(int year, int month, int day) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setInt('updatedYear', year);
await prefs.setInt('updatedMonth', month);
await prefs.setInt('updatedDay', day);
return;
}
이렇게 해서 업데이트 기능 구현이 끝났다!
영화 검색 기능도 구현 완료했고(앞의 글의 DB class에서), 업데이트 기능도 구현이 완료되었으니 핵심 기능들은 모두 구현이 끝났다.
이제는 앱 UI와 영화 정보 페이지 그리고 그 외 자잘한 기능들 구현만 남았다. (청불 차단, 광고 삽입, 검색 페이지 등등)
위의 작업들은 지금처럼 코드를 올리면 너무 방대해지니 간단간단하게 글을 쓸 예정
(github의 ChildMovie 레포에 소스코드를 올려두었으니 보고 싶으시면 ㄱㄱ)
https://github.com/harmlessman/ChildMovie
'프로젝트 > 아이의 영화' 카테고리의 다른 글
아이의 영화 앱 만들기#8-AdMob (0) | 2023.11.09 |
---|---|
아이의 영화 앱 만들기#6-DB파일&Data Model&DB Class (0) | 2023.10.31 |
아이의 영화 앱 만들기#5-자동화 (Google Cloud Run) (0) | 2023.10.24 |
아이의 영화 앱 만들기#4-데이터 저장(Firestore) (0) | 2023.10.18 |
아이의 영화 앱 만들기#3-영화 데이터(2) (0) | 2023.10.17 |