142

I need the help to query long collection with date range. See the below example document. I wanna query startTime field using date range.

enter image description here

enter image description here

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Nimer Farahty
  • 1,494
  • 2
  • 7
  • 8
  • All these answers have a huge flaw: A query can only contain ">" or "<" one one field. This means that using this approach for filtering date, will then make it impossible to filter on ranges on other fields. – Spock Jul 05 '21 at 19:37

13 Answers13

194

Since I have the dueDate field stored as "timestamp" (and NOT as string or number) on Cloud Firestore, I did this to get the invoice documents with a due date on 2017:

let start = new Date('2017-01-01');
let end = new Date('2018-01-01');

this.afs.collection('invoices', ref => ref
  .where('dueDate', '>', start)
  .where('dueDate', '<', end)
);

NOTE: dueDate field was stored at firebase with a Date() object. e.g.: this.doc.dueDate = new Date('2017-12-25')

Capy
  • 5,167
  • 2
  • 20
  • 21
  • 1
    If you take a screenshot of your firestore, is it possible from there to visually tell the difference between a datetime object or string? – DauleDK Oct 30 '17 at 07:25
  • Yes @DauleDK look: https://imgur.com/a/draQo the third field was filled with a Date() js object and it was stored as a timestamp (firebase made the convertion). And on the image you will see this timestamp formatted as UTC BUT I saved it as a Date object. And finally to check if this is really a timestamp field just hover the field. In my case I see "Marca de tiempo" which means "timestamp". – Capy Oct 30 '17 at 10:34
  • 3
    Wow that is awesome - something that should definitely be added to the firestore query documentation. I have this feeling that we will see many updates to the firebase-firestore console. "Marce de tiempo" - most valuable lesson learned today, gracias ;) – DauleDK Oct 30 '17 at 10:53
  • 4
    friends , i have try this but it returns nothing – Nimer Farahty Oct 30 '17 at 16:33
  • Also, if you are using an additional equivalence query '==', you may need to enable a composite index, the best way to do this is by catching the error, which will output a Firebase link that you can follow to auto-setup the index. My request looks like this and needed a composite_index: ```.where('team_id', '==', teamId).where('time', '>=', start).where('time', '<=', end)``` – widavies Apr 13 '20 at 00:32
46

You could store the datetime object as Unix time (seconds since 1 January 1970). Then you can simple use the where select like this:

collectionRef.where("startTime", ">=", "1506816000").where("startTime", "<=", "1507593600")

Btw - to convert from datetime to Unix time in your app, you can use the excellent (now deprecated) library moment (if you are building something with js or node).

GorvGoyl
  • 42,508
  • 29
  • 229
  • 225
DauleDK
  • 3,313
  • 11
  • 55
  • 98
32
    var startfulldate = admin.firestore.Timestamp.fromDate(new Date(1556062581000));
    db.collection('mycollection')
      .where('start_time', '<=', startfulldate)
      .get()
      .then(snapshot => {              
            var jsonvalue: any[] = [];
            snapshot.forEach(docs => {
              jsonvalue.push(docs.data())
               })
                 res.send(jsonvalue);
                 return;
                }).catch( error => {
                    res.status(500).send(error)
                });
JideGuru
  • 7,102
  • 6
  • 26
  • 48
Omar_Alvarez
  • 329
  • 3
  • 2
  • 2
    Great ! You saved my life man. I just replaced admin.firestore by firebase.firestore and it worked. – Fox5150 Jan 22 '20 at 10:05
  • 1
    This helped me immensely. I can't believe there's no documentation on Firebase for including dates in queries... – bdrelling Oct 30 '21 at 18:27
23
const event = new Date();
const expirationDate = admin.firestore.Timestamp.fromDate(event);
const query = collectionRef.where('startTime', '<=', expirationDate)
abdelhedi hlel
  • 2,903
  • 1
  • 16
  • 20
13

As startTime stored as Timestamp, you can do this query range for more accururate (this good for both condition of long date range or same date range).

const start = new Date('2021-01-01T00:00:00.000z');
const end = new Date('2021-03-01T23:59:59.000z');

db.collection('Data').where('startTime', '>=', start).where('startTime', '<=', end).get().then(data => {
   //pass your 'data' here
});

I used this in my Node.js apps. Hopefully this useful.

Utomoadito
  • 239
  • 3
  • 3
9

For everyone recently using Firebase Firestore, there's a difference depending on your settings of your Firebase implementation (depending on the firebase version).

Before, Firestore was saving Timestamp as a Date, however as described here in the docs the will be replaced soon by a Timestamp object. See the Timestamp docs here.

You can force your implementation already by adding a setting in your code to force Firebase to use Timestamp objects instead of Date like this example:

var firebaseApp = firebase.initializeApp({
    apiKey: [APIKEY],
    authDomain: [FIREBASEAPPDOMAIN],
    projectId: [PROJECTID]
});

var firestore = firebase.firestore();
var settings = { timestampsInSnapshots: true }; // force Timestamp instead of Date
firestore.settings(settings);
craft
  • 2,017
  • 1
  • 21
  • 30
ThdK
  • 9,916
  • 23
  • 74
  • 101
  • 1
    This is actually deprecated and will be removed in a future release. Firebase wants you to specify Timestamp objects specifically, going forward. – ptent May 10 '21 at 17:07
5

The solution is to use Date.now(). Stop using timestamp service from Firebase, you need to work with the numerical value of the time in milliseconds like for example: 1514271367000, instead if Firestore uses 26/12/2017 1:56:07 GMT- 0500 (-05) will not work. An example of a query is:

this.fsService.afs.collection('chats/4bY1ZpOr1TPq8bFQ3bjS/finance/123+finance/12345'
          , ref => ref.orderBy('hour').startAt(1514184967000).endAt(1514271367000))
          .valueChanges().subscribe(data =>{
            this.mensajes = data;
          })
craft
  • 2,017
  • 1
  • 21
  • 30
  • 2
    Is it okay if Firestore saves Date.now() as number data? I feel like having date is better in some cases just because of that and easiness of understanding. – Telion Jan 16 '18 at 12:21
  • 1
    This appears to be Firebase Realtime Database code (e.g. it uses `startAt` and `endAt`) not Firestore code (which would use `where`, see [here](https://firebase.google.com/docs/firestore/query-data/order-limit-data)). The two are similar, but not the same. – robsiemb Nov 07 '19 at 17:46
  • 1
    What is the timezone thought. When I determine the number, should I convert the datetime to GMT? – Csaba Toth May 18 '20 at 05:42
4

Those who, like me, are using PHP to access Firestore, can do something like this:

$startTime = new DateTime('2020-05-23 00:00:00');
$endTime = new DateTime('2020-06-23 23:59:59');

$start = new Google\Cloud\Core\Timestamp($startTime);
$end = new Google\Cloud\Core\Timestamp($endTime);

// fb is a Google\Cloud\Firestore\FirestoreClient object
$this->query = $this->fb->collection('your_collection');

$aux = $this->query;
$aux = $aux->where('startTime', '<', $end);
$aux = $aux->where('startTime', '>', $start);

return $aux->documents();

Enjoy.

Nowdeen
  • 1,401
  • 14
  • 20
0

Generic function to find documents in a collection by date range of specifics fields:

public List<QueryDocumentSnapshot> findDocsByDateRange(
                                          String collection, 
                                          String fieldStartDate,
                                          String fieldEndDate,
                                          Date startDate, 
                                          Date endDate) {
    ApiFuture<QuerySnapshot> querySnapshot = fireStore()
        .collection(collection)
            .whereGreaterThanOrEqualTo(FieldPath.of(fieldStartDate), startDate)
                .whereLessThanOrEqualTo(FieldPath.of(fieldEndDate), endDate)
                    .get();
    return querySnapshot.get().getDocuments();
}

Packages:

import com.google.api.core.ApiFuture;
import com.google.cloud.firestore.DocumentSnapshot;
import com.google.cloud.firestore.FieldPath;
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.QueryDocumentSnapshot;
import com.google.cloud.firestore.QuerySnapshot;
ℛɑƒæĿᴿᴹᴿ
  • 4,983
  • 4
  • 38
  • 58
-1

In a frontend application, this is how Firebase timestamps and dates can be used to query and store documents.

Firestore date usage

Nimesh Neema
  • 1,528
  • 2
  • 17
  • 44
x7679999
  • 17
  • 1
-1

I think this will help you out,

yourMethod() {
    var date = DateTime.now();//
    print("First Date > " + DateTime(date.year, date.month, 1).toString());
    var datex = new DateTime(date.year, date.month + 1, 0);
    print("Last Date > " +datex);//
    //
    Firestore.instance
        .collection('biling')
        .where("driverId", isEqualTo: widget.uid)
        .where("date",
            isGreaterThanOrEqualTo:
                new DateTime(date.year, date.month, 1).toString())//1
        .where("date", isLessThanOrEqualTo: datex.toString())//2
        .orderBy('date', descending: true)
        .getDocuments()
        .then(
          (QuerySnapshot snapshot) => {
            snapshot.documents.forEach((f) {
              if (this.mounted) {
                setState(() {
                  totalP += double.tryParse(f.data["price"]);
                });
              }
              print("_price " + f.data["price"]);
              print("_duePaymntForCompay " + f.data["duePaymntForCompay"]);
            }),
          },
        );
  }
gsm
  • 2,348
  • 17
  • 16
-1

now you need to use these queries for filtering documents with conditions because .where() is not working for me

  db.collection("id").whereGreaterThan("field","value")
  .whereEqualTo("field","value")
  .whereLessThen("field","value")
-2

What worked for me was Format Date with Moment JS and split into Day, Month & Year

const currentDate = moment().format("DD-MM-YYYY").split("-");
const currentDay = currentDate[0];
const currentMonth = currentDate[1];
const currentYear = currentDate[2];


const allDocuments = await collectionRef
.doc(docId)
.collection(*COLLECTION NAME*)
.where(
  *DATE PARAMETER NAME*,
  ">=",
  new Date(`${currentYear}-${currentMonth}-${currentDay}`)
)
.where(
  *DATE PARAMETER NAME*,
  "<",
// ${parseInt(currentDay) + *Number of days you want in range*} 
  new Date(`${currentYear}-${currentMonth}-${parseInt(currentDay) + 1}`)
)
.get();
Sachin Shukla
  • 335
  • 3
  • 3