I have custom class model called UserModel
and it has below fields.
final String userId;
final String name;
final String age;
final String fullBirthday;
final String gender;
final String phone;
final String fullRegion;
final String registerDate;
final int? totalScore;
final int? stepScore;
final int? diaryScore;
final int? commentScore;
And I have list
contained several these UserModels.
- I add users getting from
FireStore
to this list - I update
stepScore
,diaryScore
,commentScore
- and update
totalScore
as adding these three scores.
For the second step, I send <List<UserModel?>>
as parameter to the second step.
And as iterating this list with for in
loop, I get data from collection step, diary, comment from Firstore.
In FamilyAsyncNotifier
I send this list as paremeter, and here’s my updateScore function.
class RankingViewModel
extends FamilyAsyncNotifier<List<UserModel?>, List<UserModel?>> {
late RankingRepository _rankingRepository;
@override
FutureOr<List<UserModel?>> build(List<UserModel?> users) async {
_rankingRepository = RankingRepository();
DateTime now = DateTime.now();
DateTime firstDateOfMonth = DateTime(now.year, now.month, 1);
final updatedUsers = await updateScore(users, firstDateOfMonth, now);
return updatedUsers;
}
Future<List<UserModel?>> updateScore(
List<UserModel?> users, DateTime startDate, DateTime endDate) async {
List<UserModel?> scoreUserList = [];
for (var index = 0; index < users.length; index++) {
final String userId = users[index]!.userId;
int? stepScore =
await _rankingRepository.getStepScores(userId, startDate, endDate);
int? diaryScore =
await _rankingRepository.getDiaryScores(userId, startDate, endDate);
int? commentScore =
await _rankingRepository.getCommentScores(userId, startDate, endDate);
int? totalScore = stepScore + diaryScore + commentScore;
final updatedUser = users[index]?.copyWith(
totalScore: totalScore,
stepScore: stepScore,
diaryScore: diaryScore,
commentScore: commentScore,
);
scoreUserList.add(updatedUser);
}
return scoreUserList;
}
}
final rankingProvider = AsyncNotifierProvider.family<RankingViewModel,
List<UserModel?>, List<UserModel?>>(
() => RankingViewModel(),
);
Of course, upadteScore
function has three function to get data from collection step, diary, comment in Firestore.
That is in my repository class.
class RankingRepository {
final FirebaseFirestore _db = FirebaseFirestore.instance;
List<DateTime> getBetweenDays(DateTime startDate, DateTime endDate) {
List<DateTime> dates = [];
DateTime currentDate = startDate;
while (currentDate.isBefore(endDate) ||
currentDate.isAtSameMomentAs(endDate)) {
dates.add(currentDate);
currentDate = currentDate.add(const Duration(days: 1));
}
return dates;
}
Future<int> getStepScores(
String userId, DateTime startDate, DateTime endDate) async {
List<DateTime> betweenDates = getBetweenDays(startDate, endDate);
int stepScores = 0;
for (var date in betweenDates) {
final dateString =
"${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}";
final query = await _db.collection("user_step_count").doc(userId).get();
if (query.exists) {
final dateExists = query.data()?.containsKey(dateString);
if (dateExists!) {
dynamic diaryStepString = query.get(dateString);
final int dailyStepInt = diaryStepString as int;
final dailyScore = dailyStepInt < 0
? 0
: dailyStepInt > 10000
? 100
: ((dailyStepInt / 1000).floor()) * 10;
stepScores += dailyScore;
}
}
}
return stepScores;
}
Future<int> getDiaryScores(
String userId, DateTime startDate, DateTime endDate) async {
final query = await _db
.collection("diary")
.where("userId", isEqualTo: userId)
.where("timestamp", isGreaterThanOrEqualTo: startDate)
.where("timestamp", isLessThanOrEqualTo: endDate)
.get();
int docCount = query.docs.length;
return docCount * 100;
}
Future<int> getCommentScores(
String userId, DateTime startDate, DateTime endDate) async {
final query = await _db
.collectionGroup("comments")
.where("userId", isEqualTo: userId)
.where("timestamp", isGreaterThanOrEqualTo: startDate)
.where("timestamp", isLessThanOrEqualTo: endDate)
.get();
int docCount = query.docs.length;
return docCount * 20;
}
}
But when I run this, it takes too much time.
I think this is due to below line in updateScore
function.
int? stepScore =
await _rankingRepository.getStepScores(userId, startDate, endDate);
int? diaryScore =
await _rankingRepository.getDiaryScores(userId, startDate, endDate);
int? commentScore =
await _rankingRepository.getCommentScores(userId, startDate, endDate);
int? totalScore = stepScore + diaryScore + commentScore;
I wait for getStepScores function finished, and then wait for getDiaryScores finished..
But when I do this process same in ReactJS
, It doens’t take this this much at all as getting data from firestore and compile this data.
I want to review my process is appropriately composed for my purpose and know how to make it faster.
Please help me.
2
Answers
You can use the
Future.wait
function to achieve concurrency and optimize the code.With Dart 3 we can use the wait property of the FutureIterableExtension, which catches errors in ParallelWaitError, instead of Future.wait(), which catches only the first error.
You can then access the future by the index.