Filter and Sort Algolia results dynamically

So, I'm building a food delivery app using flutterflow and firebase as my database. And I stumbled across something a lot of people want to do. Assuming you are familiar with Algolia and to some extent querying and generating children dynamically. Here's a simple method to filter and sort the resulting json to build a listview.

Filtering

  1. Set up an API call with whatever name and add the following:

    API url: https://Your_Application_ID.algolia.net/1/indexes/Restaurants/query

    Headers- X-Algolia-API-Key: Your_API_Key

    X-Algolia-Application-Id: Your_Application_ID

    Content-Type: application/json

    Body: {

    "query": "<query>",

    "hitsPerPage": 50,

    "aroundLatLng": "<aroundLatLng>",

    "aroundRadius": 5000,

    "filters": "<filters>",

    "attributesToRetrieve": [

    "restaurantId",

    "name",

    "Tags",

    "cuisines",

    "costfortwo",

    "pureveg",

    "_geoloc"

    ]

    }

    Variables: query, aroundLatLng, filters

    And define the json paths using the results from your test api call to use later.

  2. Add the API call to your listview and pass values.

    query: *

    aroundLatLng: latlang as string not latlang

    and filters: we will use a custom function as in the attached image.

    I used a dropdown to pass the cuisine and a button to pass the pureVeg values.

Now onto Sorting

  1. We will generate children dynamically from the search results of the API call on the same listview(query with API call and generate children with the results).

  2. We will use a custom function to sort the results. You can find the function in the image too.

  3. The custom function has 3 arguments: searchResultJson(a list of json), order (a string value), jsonPath (a jsonpath string).

  4. You can use whatever method to pass the order and jsonPath but the searchResultJson will be the actual json body from the earlier API call.

    The values of order will be either asc or desc(self explanatory I think) and jsonPath value needs to be passed in this format costfortwo.

    Hit me up if you need any clarification.

import 'dart:convert';
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:timeago/timeago.dart' as timeago;
import '/flutter_flow/custom_functions.dart';
import '/flutter_flow/lat_lng.dart';
import '/flutter_flow/place.dart';
import '/flutter_flow/uploaded_file.dart';
import '/backend/backend.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '/auth/firebase_auth/auth_util.dart';

String? buildAlgoliaFilters(
  String? cuisine,
  String? pureVeg,
) {
  /// MODIFY CODE ONLY BELOW THIS LINE

  List<String> filters = [];

  if (cuisine != null && cuisine.isNotEmpty) {
    filters.add("cuisines:'$cuisine'");
  }

  if (pureVeg != null && pureVeg.isNotEmpty) {
    filters.add("pureveg:'$pureVeg'"); // โœ… Now a string: "Yes" or "No"
  }

  // โœ… If filters exist, return them as a combined string
  return filters.isNotEmpty ? filters.join(" AND ") : "";

  /// MODIFY CODE ONLY ABOVE THIS LINE
}
import 'dart:convert';
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:timeago/timeago.dart' as timeago;
import '/flutter_flow/custom_functions.dart';
import '/flutter_flow/lat_lng.dart';
import '/flutter_flow/place.dart';
import '/flutter_flow/uploaded_file.dart';
import '/backend/backend.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '/auth/firebase_auth/auth_util.dart';

List<dynamic>? sortJsonByPath(
  List<dynamic>? searchResultJson,
  String? order,
  String? jsonPath,
) {
  /// MODIFY CODE ONLY BELOW THIS LINE

  if (searchResultJson == null ||
      searchResultJson.isEmpty ||
      order == null ||
      order.isEmpty ||
      jsonPath == null ||
      jsonPath.isEmpty) {
    return null; // โœ… Return null if sorting is not possible
  }

  // โœ… Sort the List
  searchResultJson.sort((a, b) {
    dynamic valueA = _getValueFromJsonPath(a, jsonPath);
    dynamic valueB = _getValueFromJsonPath(b, jsonPath);

    // โœ… Handle null values (Move them to the end)
    if (valueA == null && valueB == null) return 0;
    if (valueA == null) return 1;
    if (valueB == null) return -1;

    // โœ… Ensure values are comparable
    if (valueA is Comparable && valueB is Comparable) {
      return (order.toLowerCase() == 'asc')
          ? valueA.compareTo(valueB)
          : valueB.compareTo(valueA);
    }

    return 0; // If values are not comparable, keep the order
  });

  // โœ… Extract and return only the sorted list of restaurant IDs
  return searchResultJson
      .map((item) => item['restaurantId'].toString())
      .toList();
}

/// **Helper Function: Extracts Value from Nested JSON**
dynamic _getValueFromJsonPath(dynamic json, String path) {
  try {
    List<String> keys =
        path.split('.'); // โœ… Support for nested paths (e.g., "address.city")
    dynamic value = json;

    for (String key in keys) {
      if (value is Map<String, dynamic> && value.containsKey(key)) {
        value = value[key];
      } else {
        return null; // โœ… If path is invalid, return null
      }
    }

    return value;
  } catch (e) {
    return null; // โœ… Handle errors gracefully
  }

  /// MODIFY CODE ONLY ABOVE THIS LINE
}
5
1 reply