【问题标题】:Firestore query by date range按日期范围查询 Firestore
【发布时间】:2026-01-24 21:20:05
【问题描述】:

我需要帮助来查询具有日期范围的长集合。请参阅以下示例文档。我想使用日期范围查询 startTime 字段。

【问题讨论】:

  • 所有这些答案都有一个巨大的缺陷:一个查询只能包含“>”或“

标签: firebase google-cloud-firestore


【解决方案1】:

由于我在 Cloud Firestore 上将 dueDate 字段存储为“时间戳”(而不是 stringnumber),因此我这样做是为了获取发票文档截止日期为 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)
);

注意: dueDate 字段使用 Date() 对象存储在 firebase。例如:this.doc.dueDate = new Date('2017-12-25')

【讨论】:

  • 如果您对 Firestore 进行截图,是否可以从那里直观地分辨出日期时间对象或字符串之间的区别?
  • 是的@DauleDK 看:imgur.com/a/draQo 第三个字段填充了一个 Date() js 对象,并存储为时间戳(firebase 进行了转换)。在图像上,您将看到此时间戳格式为 UTC 但我将其保存为 Date 对象。最后要检查这是否真的是一个时间戳字段,只需悬停该字段即可。就我而言,我看到“Marca de tiempo”,意思是“时间戳”。
  • 哇,这太棒了 - 绝对应该添加到 firestore 查询文档中。我有这种感觉,我们将看到对 firebase-firestore 控制台的许多更新。 “Marce de tiempo”——今天学到的最有价值的一课,谢谢 ;)
  • 朋友们,我试过了,但什么也没返回
  • 另外,如果您使用额外的等价查询 '==',您可能需要启用复合索引,最好的方法是捕获错误,这将输出 Firebase 链接您可以按照它来自动设置索引。我的请求看起来像这样,需要一个复合索引:.where('team_id', '==', teamId).where('time', '&gt;=', start).where('time', '&lt;=', end)
【解决方案2】:

您可以将日期时间对象存储为Unix time(自 1970 年 1 月 1 日以来的秒数)。然后你可以像这样简单地使用 where select:

collectionRef.where("startTime", "&gt;=", "1506816000").where("startTime", "&lt;=", "1507593600")

顺便说一句 - 要在您的应用程序中从日期时间转换为 Unix 时间,您可以使用出色的(现已弃用)库 moment(如果您正在使用 js 或节点构建一些东西)。

【讨论】:

  • 谢谢,但我已经有了日期格式的数据,就像随附的屏幕截图一样
  • 好的。根据firebase datetime 是firestore中支持的数据类型。 startTime 是字符串还是日期时间对象?
  • 它是 dateTime 对象它不是字符串
  • 您能否从 Firebase 控制台截取屏幕截图 - 将鼠标悬停在 startTime 上方 - 看看日期时间是否像这里 imgur.com/a/draQo
  • 添加到质疑新截图,似乎数据时间是我使用矩模块创建字段时的时间戳
【解决方案3】:
    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)
                });

【讨论】:

  • 太棒了!你救了我的命。我刚刚用 firebase.firestore 替换了 admin.firestore,它起作用了。
  • 这对我帮助很大。我不敢相信 Firebase 上没有包含查询日期的文档...
【解决方案4】:
const event = new Date();
const expirationDate = admin.firestore.Timestamp.fromDate(event);
const query = collectionRef.where('startTime', '<=', expirationDate)

【讨论】:

  • 谢谢你,这对我有帮助!
【解决方案5】:

对于最近使用 Firebase Firestore 的每个人,根据您的 Firebase 实施设置(取决于 Firebase 版本)会有所不同。

以前,Firestore 将 Timestamp 保存为 Date,但正如 here in the docs 所述,很快将被 Timestamp 对象替换。请参阅Timestamp docs here

您可以通过在代码中添加设置强制 Firebase 使用 Timestamp 对象而不是 Date 来强制实施,如下例所示:

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);

【讨论】:

  • 这实际上已被弃用,将在未来的版本中删除。 Firebase 希望您今后专门指定 Timestamp 对象。
【解决方案6】:

由于startTime存储为Timestamp,你可以做这个查询范围更准确(这对长日期范围或相同日期范围的情况都有好处)。

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
});

我在我的 Node.js 应用程序中使用了它。希望这有用。

【讨论】:

    【解决方案7】:

    像我一样使用 PHP 访问 Firestore 的人可以这样做:

    $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();
    

    享受吧。

    【讨论】:

      【解决方案8】:

      解决方案是使用 Date.now()。停止使用 Firebase 的时间戳服务,您需要使用以毫秒为单位的时间数值,例如:1514271367000,如果 Firestore 使用 26/12/2017 1:56:07 GMT-0500 (-05) 将不起作用.查询示例如下:

      this.fsService.afs.collection('chats/4bY1ZpOr1TPq8bFQ3bjS/finance/123+finance/12345'
                , ref => ref.orderBy('hour').startAt(1514184967000).endAt(1514271367000))
                .valueChanges().subscribe(data =>{
                  this.mensajes = data;
                })
      

      【讨论】:

      • Firestore 将 Date.now() 保存为数字数据可以吗?我觉得在某些情况下约会会更好,因为这和易于理解。
      • 这似乎是 Firebase 实时数据库代码(例如,它使用 startAtendAt)而不是 Firestore 代码(将使用 where,请参阅 here)。两者相似,但又不相同。
      • 时区的想法是什么。当我确定数字时,我应该将日期时间转换为 GMT 吗?
      【解决方案9】:

      我想这会对你有所帮助,

      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"]);
                  }),
                },
              );
        }
      

      【讨论】:

        【解决方案10】:

        按特定字段的日期范围在集合中查找文档的通用函数:

        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();
        }
        

        包:

        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;
        

        【讨论】:

          【解决方案11】:

          在前端应用程序中,这就是 Firebase 时间戳和日期可用于查询和存储文档的方式。

          【讨论】:

          • 你好。尽可能多的外部链接可能有用,请将您的答案内容直接插入 SO。
          【解决方案12】:

          对我有用的是 使用 Moment JS 格式化日期并拆分为日、月和年

          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();
          

          【讨论】: