Ich versuche herauszufinden, wie ein Firestore-Zeitstempel in einer Reaktions-App angezeigt wird.
Ich habe ein Firestore-Dokument mit einem Feld namens createdAt.
Ich versuche, es in eine Liste der Ausgaben aufzunehmen (hier werden die relevanten Bits extrahiert, damit Sie nicht die gesamte Liste der Felder durchlesen müssen).
componentDidMount() {
this.setState({ loading: true });
this.unsubscribe = this.props.firebase
.users()
.onSnapshot(snapshot => {
let users = [];
snapshot.forEach(doc =>
users.push({ ...doc.data(), uid: doc.id }),
);
this.setState({
users,
loading: false,
});
});
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const { users, loading } = this.state;
return (
<div>
{loading && <div>Loading ...</div>}
{users.map(user => (
<Paragraph key={user.uid}>
<key={user.uid}>
{user.email}
{user.name}
{user.createdAt.toDate()}
{user.createdAt.toDate}
{user.createdAt.toDate()).toDateString()}
Das einzige Attribut, das nicht gerendert wird, ist das Datum.
Jeder der oben genannten Versuche erzeugt einen Fehler, der besagt:
TypeError: Die Eigenschaft 'toDate' von undefined kann nicht gelesen werden
Ich habe diesen Beitrag und diesen Beitrag und diesen Beitrag und diesen Beitrag und andere wie sie gesehen, die darauf hinweisen, dass toDate () funktionieren sollte. Aber - diese Erweiterung wirft einen Fehler für mich auf - auch wenn ich die toString-Erweiterung versuche.
Ich weiß, dass es weiß, dass es etwas im Firestore gibt, denn wenn ich user.createdAt versuche, erhalte ich eine Fehlermeldung, dass ein Objekt mit Sekunden darin gefunden wurde.
Am Beispiel von Waelmas unten habe ich versucht, die Ausgabe des Feldes wie folgt zu protokollieren:
this.db.collection('users').doc('HnH5TeCU1lUjeTqAYJ34ycjt78w22').get().then(function(doc) {
console.log(doc.data().createdAt.toDate());
}}
Ich habe auch versucht, dies zu meiner Map-Anweisung hinzuzufügen, erhalte jedoch eine Fehlermeldung, dass user.get keine Funktion ist.
{user.get().then(function(doc) {
console.log(doc.data().createdAt.toDate());}
)}
Es wird dieselbe Fehlermeldung wie oben generiert.
NÄCHSTER VERSUCH
Eine seltsame Sache, die bei dem Versuch aufgetaucht ist, einen Weg zu finden, ein Datum in Firestore aufzuzeichnen, der es mir ermöglicht, es dann zurückzulesen, ist, dass ich meinen Submit-Handler in einer Form ändere, um diese Formulierung zu verwenden:
handleCreate = (event) => {
const { form } = this.formRef.props;
form.validateFields((err, values) => {
if (err) {
return;
};
const payload = {
name: values.name,
// createdAt: this.fieldValue.Timestamp()
// createdAt: this.props.firebase.fieldValue.serverTimestamp()
}
console.log("formvalues", payload);
// console.log(_firebase.fieldValue.serverTimestamp());
this.props.firebase
.doCreateUserWithEmailAndPassword(values.email, values.password)
.then(authUser => {
return this.props.firebase.user(authUser.user.uid).set(
{
name: values.name,
email: values.email,
createdAt: new Date()
// .toISOString()
// createdAt: this.props.firebase.fieldValue.serverTimestamp()
},
{ merge: true },
);
// console.log(this.props.firebase.fieldValue.serverTimestamp())
})
.then(() => {
return this.props.firebase.doSendEmailVerification();
})
// .then(() => {message.success("Success") })
.then(() => {
this.setState({ ...initialValues });
this.props.history.push(ROUTES.DASHBOARD);
})
});
event.preventDefault();
};
Das funktioniert, um ein Datum in der Datenbank aufzuzeichnen.
Die Form des Firestore-Eintrags sieht folgendermaßen aus:
Ich versuche, ein Datum in dieser Komponente anzuzeigen:
class UserList extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
users: [],
};
}
componentDidMount() {
this.setState({ loading: true });
this.unsubscribe = this.props.firebase
.users()
.onSnapshot(snapshot => {
let users = [];
snapshot.forEach(doc =>
users.push({ ...doc.data(), uid: doc.id }),
);
this.setState({
users,
loading: false,
});
});
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const { users, loading } = this.state;
return (
<div>
{loading && <div>Loading ...</div>}
<List
itemLayout="horizontal"
dataSource={users}
renderItem={item => (
<List.Item key={item.uid}>
<List.Item.Meta
title={item.name}
description={item.organisation}
/>
{item.email}
{item.createdAt}
{item.createdAt.toDate()}
{item.createdAt.toDate().toISOString()}
</List.Item>
// )
)}
/>
</div>
);
}
}
export default withFirebase(UserList);
Wenn ich versuche, es zurückzulesen - mit:
{item.email}
Die Fehlermeldung lautet:
Fehler: Objekte sind als untergeordnetes Element nicht gültig (gefunden: Zeitstempel (Sekunden = 1576363035, Nanosekunden = 52000000)). Wenn Sie eine Sammlung von untergeordneten Elementen rendern möchten, verwenden Sie stattdessen ein Array. in Item (unter UserIndex.jsx: 74)
Wenn ich versuche, jeden dieser Versuche zu verwenden:
{item.createdAt}
{item.createdAt.toDate()}
{item.createdAt.toDate().toISOString()}
Ich erhalte eine Fehlermeldung:
TypeError: Die Eigenschaft 'toDate' von undefined kann nicht gelesen werden
Aufgrund der Möglichkeit, Einträge, die im selben Dokument protokolliert wurden, in anderen Feldern zurückzulesen, erwarte ich, dass diese Einträge auch dann zur Ausgabe führen, wenn sie nicht wie gewünscht formatiert sind. Das passiert nicht
NÄCHSTER VERSUCH
Am Beispiel von Waelmas habe ich versucht, den Anweisungen zu folgen, aber wo wir nicht die gleiche Antwort erhalten, ist der erste Schritt. Wenn Walemas eine Ausgabe basierend auf der Erweiterung .toDate () erhält, wird die Fehlermeldung angezeigt, dass toDate () keine Funktion ist.
In Übereinstimmung mit der Firebase-Dokumentation habe ich versucht:
const docRef = this.props.firebase.db.collection("users").doc("HnH5TeCU1lUjeTqAYJ34ycjt78w22");
docRef.get().then(function(docRef) {
if (doc.exists) {
console.log("Document createdAt:", docRef.createdAt.toDate());
}})
Dies führt zu einer Reihe von Fehlern in der Syntax, und ich kann sie nicht umgehen.
NÄCHSTER VERSUCH
Ich habe dann versucht, ein neues Formular zu erstellen, um zu prüfen, ob ich dies ohne den Authentifizierungsaspekt des Benutzerformulars untersuchen kann.
Ich habe ein Formular, das folgende Eingaben enthält:
this.props.firebase.db.collection("insights").add({
title: title,
text: text,
// createdAt1: new Date(),
createdAt: this.props.firebase.fieldValue.serverTimestamp()
})
Während im vorherigen Formular der neue Date () - Versuch versucht hat, ein Datum in der Datenbank aufzuzeichnen, generieren in diesem Beispiel beide Felder für createdAt und createdAt1 denselben Datenbankeintrag:
<div>{item.createdAt.toDate()}</div>
<div>{item.createdAt.toDate()}</div>
Wenn ich versuche, den Wert der Daten auszugeben, generiert der erste einen Fehler, der besagt:
Objekte sind als React-Kind nicht gültig (gefunden: So 15.12.2019 21:33:32 GMT + 1100 (Australian Eastern Daylight Time)). Wenn Sie eine Sammlung von untergeordneten Elementen rendern möchten, verwenden Sie stattdessen ein Array
Der zweite generiert den Fehler:
TypeError: Die Eigenschaft 'toDate' von undefined kann nicht gelesen werden
Ich bin gespannt auf Ideen, was ich als nächstes versuchen soll.
Ich habe diesen Beitrag gesehen , der darauf hindeutet, dass Folgendes etwas Nützliches bewirken könnte:
{item.createdAt1.Date.valueOf()}
Das tut es nicht. Es wird ein Fehler ausgegeben, der besagt:
TypeError: Die Eigenschaft 'Date' von undefined kann nicht gelesen werden
Dieser Beitrag scheint die gleichen Probleme zu haben wie ich, geht aber nicht darauf ein, wie sie es geschafft haben, den von ihnen gespeicherten Datumswert anzuzeigen.
Dieser Beitrag scheint bei der Array-Fehlermeldung hängen zu bleiben, scheint aber herausgefunden zu haben, wie ein Datum mit createdAt.toDate () angezeigt wird.
Wenn Sie Zeitstempel von Firestore erhalten, sind diese vom folgenden Typ:
Um dies in einen normalen Zeitstempel umzuwandeln, können Sie die Funktion .toDate () verwenden.
Zum Beispiel für ein Dokument wie das folgende:
Wir können so etwas verwenden wie:
und die Ausgabe wird wie folgt sein:
Um diesen Zeitstempel weiter zu verarbeiten, können Sie ihn in eine Zeichenfolge konvertieren und mithilfe von Regex entsprechend Ihren Anforderungen ändern.
Zum Beispiel: (Ich verwende hier Node.js)
Gibt Ihnen eine Ausgabe wie folgt:
quelle
Der Firestore speichert also Daten als Objekt mit Sekunden und Nanosekunden. Wenn Sie die Zeit angeben möchten, zu der der Benutzer erstellt wurde, verweisen Sie darauf
user.createdAt.nanoseconds
. Dies gibt einen Unix-Zeitstempel zurück.Wie möchten Sie das Datum in Ihrer App anzeigen? Wenn Sie ein Datumsobjekt erhalten möchten, können Sie den Zeitstempel wie folgt an einen Datumskonstruktor übergeben
new Date(user.createdAt.nanoseconds)
. Persönlich genieße ich es, die date-fns- Bibliothek für den Umgang mit der Zeit zu verwenden.quelle
user.createdAt && new Date(user.createdAt.nanoseconds)
. Date-fns hilft bei diesem Problem nicht weiter, sondern nur eine praktische Bibliothek zum Anzeigen des Datums, sobald Sie es haben.firestore.FieldValue.serverTimestamp()
So senden Sie das Datum an Firestore:
Wie man es zurückliest:
Grundsätzlich erhalten
createdAt.toDate()
Sie dabei ein JS Date-Objekt.Ich benutze es die ganze Zeit so!
Von: https://cloud.google.com/firestore/docs/manage-data/add-data
Dadurch werden Daten basierend auf dem Systemdatum des Benutzers erstellt. Wenn Sie sicherstellen müssen, dass alles chronologisch (ohne Fehler falscher Systemdaten, die von Ihrem Benutzersystem festgelegt wurden) in Ihrer Datenbank gespeichert wird, sollten Sie einen Server-Zeitstempel verwenden. Das Datum wird mit Ihrem internen Datumssystem von Firestore DB festgelegt.
quelle
createdAt
Versuchen Sie Folgendes mit einer Dokument-ID eines Benutzers, für den die Eigenschaft festgelegt wurde:Es ist wichtig, die
.data()
Methode aufzurufen , bevor Sie auf die Eigenschaften des Dokuments zugreifenBeachten Sie, dass Sie erhalten, wenn Sie auf
docRef.data().createdAt.toDate()
einen Benutzer zugreifen, für den diecreatedAt
Eigenschaft nicht festgelegt istTypeError: Cannot read property 'toDate' of undefined
Falls Sie also einen Benutzer in Ihrer Sammlung haben, für den keine
createdAt
Eigenschaft definiert ist. Sie sollten eine Logik implementieren, um zu überprüfen, ob der Benutzer über diecreatedAt
Eigenschaft verfügt, bevor Sie sie abrufen. Sie können so etwas tun:quelle
Ich habe in der Vergangenheit Probleme mit verschachtelten Objekteigenschaften festgestellt, die in Listen, die
item.someProp
als Objekt betrachtet werden, nicht ordnungsgemäß gerendert werden , aberitem.someProp.someSubProp
mit dem Wert vonsomeSubProp
in nicht behoben werden könnenitem.someProp
.Um das Problem zu umgehen, sollten Sie beim Erstellen des Benutzerobjekts den Zeitstempel auf ein einfaches Datumsobjekt (oder das gewünschte Anzeigeformat) auswerten.
quelle
DocumentSnapshot#data()
undDocumentSnapshot#get()
ein Objekt akzeptieren, das angibt, wie mit noch nicht finalisiertenFieldValue.serverTimestamp()
Werten umgegangen werden soll. Standardmäßig ist ein noch nicht abgeschlossener Wert einfach null. Mit{ serverTimestamps: "estimate"}
wird diese Nullwerte in eine Schätzung geändert.