skip to Main Content

I’m building a Flutter app with Firestore as the backend database. I have a collection of products, and I’m trying to implement a search functionality that filters products based on a search text and the search is totally generic as it can provide search results regardless of the category of product

class ProductGrid extends StatefulWidget {
  final String selectedCategory;
  final String searchText;

  const ProductGrid(
      {Key? key, required this.selectedCategory, required this.searchText})
      : super(key: key);

  @override
  State<ProductGrid> createState() => _ProductGridState();
}

class _ProductGridState extends State<ProductGrid> {
  @override
  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Expanded(
      child: StreamBuilder<QuerySnapshot>(
        stream: FirebaseFirestore.instance
            .collection('users')
            .doc(FirebaseAuth.instance.currentUser!.uid)
            .collection('products')
            .where('selectedCategory',
                isEqualTo: widget.selectedCategory.isNotEmpty
                    ? widget.selectedCategory
                    : null)
            .where('title', // Filter products by title based on searchText
                isGreaterThanOrEqualTo: widget.searchText.toLowerCase(),
                isLessThanOrEqualTo: widget.searchText.toLowerCase() + 'z')
            .snapshots(),
        builder: (context, snapshot) {
          print('this: ${widget.searchText}');
          print('$snapshot');
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(
                child: SpinKitRing(color: primaryBlue, size: 30));
          } else if (snapshot.hasData) {
            List<Map<String, dynamic>> productsList = snapshot.data!.docs
                .map((doc) => doc.data() as Map<String, dynamic>)
                .toList();
            return GridView.builder(
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                childAspectRatio: 0.88,
                mainAxisSpacing: size.height * 0.01,
                crossAxisSpacing: size.width * 0.017,
              ),
              itemCount: productsList.length,
              itemBuilder: (context, index) {
                Map<String, dynamic> productData = productsList[index];
                return Container(
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(20),
                    color: Colors.white,
                  ),
                  child: //rest of the code
                          ),
                          child: //rest of the code
                                  ),
                                );
                              },
                              child: Image.asset(
                                'assets/images/iphoneImage.png',
                              ),
                            ),
                          ),
                        ),
                        SizedBox(height: size.height * 0.015),
                        Padding(
                          padding: const EdgeInsets.only(left: 12),
                          child: Row(
                            children: [
                              Text(
                                productData['title'],
                                style: customTextblack,
                              ),
                              //remaining code fetching titles and products from databse
                            ],
                          ),
                        ),
                        //remaining code
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                );
              },
            );
          } else {
            return CircularProgressIndicator();
          }
        },
      ),
    );
  }
}

However, when I type a search query in my app, the query doesn’t return any results, even though I have products that match the search text.

I’ve ensured that the search text matches the titles of some products in my database, and the category filtering seems to be working correctly.

Could someone please help me identify why the Firestore query is not returning any results, even though there should be matching products in the database? Any insights or suggestions would be greatly appreciated. Thank you!

My App bar code just incase if you want to have a look into it

class AppSearchBar extends StatelessWidget {
  final ValueChanged<String> onChanged;
  final String hintText;
  const AppSearchBar(
      {super.key, required this.hintText, required this.onChanged});

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Container(
      height: size.height * 0.06,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(30),
        color: Colors.white,
      ),
      child: Center(
        child: TextFormField(
            onChanged: onChanged,
            decoration: InputDecoration(
                contentPadding: const EdgeInsets.all(12.0),
                prefixIcon: Padding(
                  padding: const EdgeInsets.all(10.0),
                  child: SvgPicture.asset(
                    'assets/images/magnifyingglass.svg',
                  ),
                ),
                iconColor: const Color(0xffC2C2C2),
                border: InputBorder.none,
                hintText: hintText,
                hintStyle: lowOpacityText)),
      ),
    );
  }
}

2

Answers


  1. In your firbase quary change like this

    FirebaseFirestore.instance
            .collection('users')
            .doc(FirebaseAuth.instance.currentUser!.uid)
            .collection('products')
            .where('selectedCategory',
                isEqualTo: widget.selectedCategory.isNotEmpty
                    ? widget.selectedCategory
                    : null)
            //change this
            .orderBy('title').
            .startAt([widget.searchText.toLowerCase()])    
            .snapshots(),
    
    Login or Signup to reply.
  2. This seems wrong:

    .where('title', // Filter products by title based on searchText
        isGreaterThanOrEqualTo: widget.searchText.toLowerCase(),
        isLessThanOrEqualTo: widget.searchText.toLowerCase() + 'z')
    

    As far as I know, the correct syntax is:

    .where('title', isGreaterThanOrEqualTo: widget.searchText.toLowerCase()),
    .where('title', isLessThanOrEqualTo: widget.searchText.toLowerCase() + 'z'))
    

    you’ll also wan to make sure that you have the required index, as what is needed here isn’t auto-created.


    Your builder fails to handle errors from the Firestore stream, which is probably why you don’t see any errors. Every builder should start with something like this:

    builder: (context, snapshot) {
      if (snapshot.hasError) {
        print('ERROR: ${snapshot.error}');
        return Text('ERROR: ${snapshot.error}');
      }
      print('this: ${widget.searchText}');
      print('$snapshot');
      if (snapshot.connectionState == ConnectionState.waiting) {
        ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search