skip to Main Content

In my list from the Firebase database, I want the user to be able to sort the list with date range. Thus choosing dates and displaying only the data based on the chosen date range.
My data contains the following fields:

1) "Date" : DateFormat("dd-MMM-yyyy").format(DateTime.now),
2) "Timestamp": Timestamp.now(),

In my code, I have the DateTimeRange already. How do I implement the function where the UI shows only the data within that range after the user selects the date range?

DateTimeRange? dateRange;
Future pickDateRange() async {
    final initialDateRange = DateTimeRange(
      start: DateTime.now(),
      end: DateTime.now(),
    );
    final newDateRange = await showDateRangePicker(
      context: context,
      firstDate: DateTime(DateTime.now().year - 20),
      lastDate: DateTime(DateTime.now().year + 20),
      initialDateRange: dateRange ?? initialDateRange,
    );
    if (newDateRange == null) {
      return;
    } else {
      setState(() => dateRange = newDateRange);
    }
  }

TextButton(
     onTap: () => pickDateRange()
     )

StreamBuilder(
              stream: FirebaseFirestore.instance
                  .collectionGroup(widget.dailyTransactionsCollection)
                  .orderBy("Timestamp", descending: true)
                  .snapshots(),
              builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return const CircularProgressIndicator();
                } else if (snapshot.hasError) {
                  return Text(
                    widget.errorString,
                    style: const TextStyle(color: Colors.white),
                  );
                }
                if (snapshot.hasData) {
                  return ListView.builder(
                    itemCount: snapshot.data!.docs.length,
                    itemBuilder: (context, index) {
                      final data = snapshot.data!.docs[index];
                      final date = data["Date"];
                      final amount = data["Amount"];
                      final timestamp = data["Timestamp"];
                      if (dateRange == null) {
                        return ListTile(
                          title: Row(
                            children: [
                              Padding(
                                padding: const EdgeInsets.only(left: 50),
                                child: SizedBox(
                                  width: screenWidth * 0.1,
                                  child: Text(
                                    date,
                                  ),
                                ),
                              ),
                              Padding(
                                padding: const EdgeInsets.only(left: 100),
                                child: SizedBox(
                                  width: screenWidth * 0.2,
                                  child: Text("$amount"),
                                ),
                              )
                            ],
                          ),
                        );
                      } else {
                       /* I want the function to return the same ListTile as the 
                       one above, but only this time, the data should be within 
                        the date range selected
                        */
                      }
                    },
                  );
                }
                return Center(
                  child: Text(widget.noDataYetString),
                );
              },
            ),

2

Answers


  1. Chosen as BEST ANSWER
    DateTime? firstDate;
    DateTime? secDate;
    Future pickFirstDate() async {
        final initialDate = DateTime.now();
        final newDate = await showDatePicker(
          context: context,
          initialDate: firstDate ?? initialDate,
          firstDate: DateTime(DateTime.now().year - 20),
          lastDate: DateTime.now(),
        );
        if (newDate == null) {
          return;
        }
        setState(() => firstDate = newDate);
      }
    
      Future pickSecDate() async {
        final initialDate = DateTime.now();
        final newDate = await showDatePicker(
          context: context,
          initialDate: secDate ?? initialDate,
          firstDate: DateTime(DateTime.now().year - 10),
          lastDate: DateTime.now(),
        );
        if (newDate == null) {
          return;
        }
        setState(() => secDate = newDate);
      }
    StreamBuilder(
       stream: firstDate != null && secDate != null
                      ? FirebaseFirestore.instance
                          .collectionGroup(widget.dailyTransactionsCollection)
                          .where("Date",
                              isGreaterThanOrEqualTo: firstDate,
                              isLessThanOrEqualTo: secDate)
                          .orderBy("Date", descending: true)
                          .snapshots()
                      : FirebaseFirestore.instance
                          .collectionGroup(widget.dailyTransactionsCollection)
                          .orderBy("Date", descending: true)
                          .snapshots(),
         builder: (context, snapshot){
     /*This actually solved it*/
             }
          )
    

  2. Firestore queries can only contain inequality conditions (things like >, >=, <>, etc) on a single field. From the documentation on query limitations:

    In a compound query, range (<, <=, >, >=) and not equals (!=, not-in) comparisons must all filter on the same field

    So in your current data model, you can select one specific date (with a == condition on Date) and then select a time range (with >= and <= conditions on Timestamp). But you can’t select a start and end time across multiple dates with your current data model.

    To allow that, you’ll have to change your data model and store the exact timestamp in a single field (of type Timestamp). Once you have that, you can put >= and <= conditions on that single field, and implement the use-case.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search