Est-il possible d'interroger les documents Firestore par updateTime
. Le champ disponible à partir de l'instantané du document sous le nom doc.updateTime
et l'utiliser dans une requête where?
J'utilise le sdk node.js.
3 Réponses :
Autant que je sache, il n'y a aucun moyen d'interroger les métadonnées que Firestore maintient automatiquement. Si vous devez interroger la dernière date de mise à jour, vous devrez ajouter un champ avec cette valeur aux données du document.
C'est vrai, il n'y a pas de requête pour l'heure de création / modification, mais lorsque vous récupérez un document, ces champs existent dans la charge utile. Vous avez:
payload.doc ['_ document']. proto.createTime
et payload.doc['_document' Often.proto.updateTime
Bien sûr, ce n'est pas une bonne pratique de s'appuyer sur des champs privés, il faudra donc probablement des ajustements continus au fur et à mesure que Firestore modifie son modèle de données, mais pour l'instant, pour mes utilisations, cela me donne ces données autrement impossibles à interroger. >
J'ai vraiment besoin d'interroger Firebase sur le document _updateTime, j'ai donc écrit une fonction qui copie cet horodatage interne caché dans un champ interrogeable. Cela a pris du travail pour comprendre cela, donc je publie la solution complète. (Techniquement, il s'agit de "Cloud Firestore" plutôt que de "Realtime Database".)
Ceci est fait en utilisant Firebase Functions, qui lui-même a nécessité quelques essais pour fonctionner. Ce tutoriel s'est avéré utile:
https://firebase.google. com / docs / functions / get-started
Cependant, sous Windows 10, la seule ligne de commande qui fonctionnait était le nouveau shell Bash, disponible depuis 2017 environ. installer, mais nécessaire. Le shell GIT Bash, par ailleurs très utile, n'a pas été en mesure de suivre les positions de l'écran lors de la configuration du projet Firebase.
Dans mon exemple de code, j'ai laissé dans toutes les instructions 'console.log', pour afficher détail. Ce n'est pas évident au début où vont ces journaux. Ils ne vont pas à la ligne de commande, mais à la console Firebase:
https://console.firebase.google.com/u/0/
sous (votre projet)> Fonctions> Journaux
Pour les tests, je l'ai trouvé utile pour, au début, déployer une seule fonction (c'est dans la CLI):
// 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 } });
Voici ma fonction de travail, fortement commentée, et avec une certaine redondance à titre d'illustration. Remplacez 'PlantSpp' par le nom de votre collection de documents:
firebase deploy --only functions:testFn