I am making a flutter application and I’m using cloud firestore as my online database. One of the features in my app is looking for nearby users and showing their profile to the current user in a custom widget on screen. The way I do it is I get current user’s location (either live location or the address saved in database) and then go through every single user in my database collection for users. I get the address of the user from the stored data, calculate the distance using Distance Matrix API and then if distance is less than a specific number (e.g 10000 meter) I create the profile widget for the user to show it on screen.
There are 2 problems:
1- if my number of users grows (for example a million users), By going through every user detail and calculating the distance, It can take a really long time to get the results on the screen . Right now, I only have 20 users for testing purposes and when I search for nearby users, it can take 30 seconds for the results to show up on the screen.
2- With a slow internet connection, the waiting time can be much much more and it can use lots of user’s data for this simple task.
How can I improve this feature and make it faster?
(The current idea that I have is dividing user’s in different documents with respect to their location and then going through only one of the documents by using current user’s location. The problem is that how to divide the addresses efficiently and find the best addresses to look for.)
Below is the code where I find nearby users and add them to a list which I pass to my custom widget class.
final List<UserBoxDesign> listOfBoxes = [];
final FirebaseUser currentUser = await auth.currentUser();
final String currentUserId = currentUser.uid;
if (_userLocationSwitchValue == false) { //use default address of the user
currentUserAddress = await _databaseManagement.getUserCollectionValues(
currentUserId, "address");
} else {
//currentUserAddress = //to do, get device location here.
}
if (_searchValue == SearchValues.Users) {
final List<String> userIds = await _databaseManagement.getUserIds();
for (String id in userIds) {
final String otherUserLocations =
await _databaseManagement.getUserCollectionValues(id, "address");
final String distanceMeters = await _findDistanceGoogleMaps(
currentUserAddress, otherUserLocations);
if (distanceMeters == "Address can't be calculated" ||
distanceMeters == "Distance is more than required by user") {
//if it's not possible to calculate the address then just don't do anything with that.
} else {
final double distanceValueInKilometers = (double.parse(
distanceMeters) /
1000)
.roundToDouble();
final String userProfileImageUrl =
await _databaseManagement.getUserCollectionValues(id, "image");
final String username =
await _databaseManagement.getUserCollectionValues(id, "username");
listOfBoxes.add(
UserBoxDesign( //it creates a custom widget for user if user is nearby
userImageUrl: userProfileImageUrl,
distanceFromUser: distanceValueInKilometers,
userId: id,
username: username,
),
); //here we store the latest values inside the reserved data so when we create the page again, the value will be the reservedData value which is not empty anymore
}
print(listOfBoxes);
}
listOfBoxes.sort((itemA,itemB)=>itemA.distanceFromUser.compareTo(itemB.distanceFromUser)); //SORTs the items from closer to more far from user (we can reverse it to far comes first and close goes last)
setState(() {
_isSearchingForUser = false;
});
return listOfBoxes;
Here is the code where I calculate the distance between origin address and destination address.
Future<String> _findDistanceGoogleMaps(
String originAddress, String destinationAddress) async {
final String url =
"https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=$originAddress&destinations=$destinationAddress&key=$GoogleMapsAPIKey";
try {
final response = await http.get(url);
final responseDecoded = json.decode(response.body);
final distanceInMeters = double.parse(responseDecoded["rows"][0]
["elements"][0]["distance"]["value"]
.toString()); //this is the value in meters always so for km , divide by 1000.
if (distanceInMeters < 100000) {
return distanceInMeters.toString();
} else {
return "Distance is more than required by user";
}
} catch (e) {
return "Address can't be calculated";
}
}