如何通过文档快照的更新时间查询Firestore?

6

是否可以通过updateTime查询firestore文档。从文档快照中作为doc.updateTime可用的字段,并在where查询中使用它?

我正在使用node.js SDK。

3个回答

6
据我所知,目前无法查询Firestore自动维护的元数据。如果您需要查询最后更新日期,则需要在文档数据中添加一个具有该值的字段。

2
我真的需要在Firebase上查询文档_updateTime,所以我编写了一个函数,将该隐藏的内部时间戳复制到可查询的字段中。这需要一些工作才能弄清楚,所以我发布了完整的解决方案。(从技术上讲,这是“云Firestore”而不是“实时数据库”。)
这是使用Firebase Functions完成的,它本身需要一些尝试才能正常工作。这个教程很有帮助:

https://firebase.google.com/docs/functions/get-started

然而,在Windows 10上,唯一有效的命令行是自2017年左右推出的新Bash shell。虽然安装有些麻烦,但却是必要的。GIT Bash shell虽然非常有用,但在Firebase项目设置期间无法跟踪屏幕位置。
在我的示例代码中,我保留了所有的“console.log”语句以显示细节。一开始并不明显的是这些日志的输出位置。它们不会输出到命令行,而是输出到Firebase控制台。

https://console.firebase.google.com/u/0/

在(您的项目)下>函数>日志
为了测试,我发现最好只部署一个函数(这是在CLI中):
firebase deploy --only functions:testFn

以下是我的工作函数,有很多注释,并且为了说明某些内容而存在一些冗余。请用你的文档集合名称替换“PlantSpp”:

// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');

// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();

// Firestore maintains an interal _updateTime for every document, but this is
// not queryable. This function copies that to a visible field 'Updated'
exports.makeUpdateTimeVisible = functions.firestore
      .document('PlantSpp/{sppId}')
      .onWrite((sppDoc, context) => {
  console.log("Event type: ", context.eventType);
  // context.eventType = 'google.firestore.document.write', so cannot use
  // to distinguish e.g. create from update
  const docName = context.params.sppId // this is how to get the document name
  console.log("Before: ", sppDoc.before); // if a create, a 'DocumentSnapshot',
  // otherwise a 'QueryDocumentSnapshot'
  // if a create, everything about sppDoc.before is undefined
  if (typeof sppDoc.before._fieldsProto === "undefined"){
    console.log('document "', docName, '" has been created');
    // set flags here if desired
  }
  console.log("After: ", sppDoc.after); // if a delete, a 'DocumentSnapshot',
  // otherwise a 'QueryDocumentSnapshot'
  // if a delete, everything about sppDoc.after is undefined
  if (typeof sppDoc.after._fieldsProto === "undefined"){
    console.log('document "', docName, '" has been deleted');
    // other fields could be fetched from sppDoc.before
    return null; // no need to proceed
  }
  console.log(sppDoc.after.data()); // the user defined fields:values
  // inside curly braces
  console.log(sppDoc.after._fieldsProto); // similar to previous except with
  // data types, e.g.
  // data() has { Code: 'OLDO',...
  // _fieldsProto has { Code: { stringValue: 'OLDO' },...
  const timeJustUpdated = sppDoc.after._updateTime; // this is how to get the
  // internal nonqueryable timestamp
  console.log(timeJustUpdated);
  //  e.g.      Timestamp { _seconds: 1581615533, _nanoseconds: 496655000 }
  //  later:    Timestamp { _seconds: 1581617552, _nanoseconds: 566223000 }
  // shows this is correctly updating
  // see if the doc has the 'Updated' field yet
  if (sppDoc.after._fieldsProto.hasOwnProperty('Updated')) {
    console.log("doc has the field 'Updated' with the value",
                  sppDoc.after._fieldsProto.Updated);
    console.log("sppDoc:", sppDoc);
    const secondsInternal = timeJustUpdated._seconds;
    console.log(secondsInternal, "seconds, internal timestamp");
    const secondsExternal = sppDoc.after.data().Updated._seconds;
    console.log(secondsExternal, "seconds, external timestamp");
    // Careful here. If we just update the externally visible time to the
    // internal time, we will go into an infinite loop because that update
    // will call this function again, and by then the internal time will have
    // advanced
    // the following exit will not work:
    if (secondsInternal === secondsExternal) return null; // will never exit
    // instead, allow the external time to lag the internal by a little
    const secondsLate = secondsInternal - secondsExternal;
    if (secondsLate < 120) { // two minutes sufficient for this purpose
      console.log("the field 'Updated' is", secondsLate,
                  "seconds late, good enough");
       return null;
    }
    console.log("the field 'Updated' is", secondsLate,
                  "seconds late, updating");
    // return a promise of a set operation to update the timestamp
    return sppDoc.after.ref.set({
      Updated: timeJustUpdated
    }, {merge: true}); // 'merge' prevents overwriting whole doc
    // this change will call this same function again
  } else { // field 'Updated' does not exist in the document yet
    // this illustrates how to add a field
    console.log("doc does not have the field 'Updated', adding it now.");
    // return a promise of a set operation to create the timestamp
    return sppDoc.after.ref.set({
      Updated: timeJustUpdated
    }, {merge: true}); // 'merge' prevents overwriting the whole doc
    // this change will call this same function again
  }
});


1

确实,没有关于创建/修改时间的查询,但是当您获取文档时,这些字段存在于负载中。您可以使用:

payload.doc['_document'].proto.createTimepayload.doc['_document'].proto.updateTime

当然,依赖私有字段并不是一个好的做法,因此可能需要随着Firestore更改其数据模型而进行持续调整,但目前对于我的用途,它使我获得了这些无法查询的数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接