Estoy tratando de descubrir cómo mostrar una marca de tiempo de la tienda de incendios en una aplicación de reacción.
Tengo un documento de almacén de incendios con un campo llamado createdAt.
Estoy tratando de incluirlo en una lista de resultados (extrayendo los bits relevantes aquí para que no tenga que leer toda la lista de campos).
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()}
El único atributo que no se procesará es la fecha.
Cada uno de los intentos anteriores genera un error que dice:
TypeError: no se puede leer la propiedad 'toDate' de undefined
He visto esta publicación , y esta publicación y esta publicación , y esta publicación y otras similares, que sugieren que toDate () debería funcionar. Pero, esta extensión arroja un error para mí, incluso cuando intento la extensión toString.
Sé que sabe que hay algo en el almacén de incendios porque cuando intento user.createdAt, recibo un error que dice que encontró un objeto con segundos en él.
Tomando el ejemplo de Waelmas a continuación, traté de registrar la salida del campo como:
this.db.collection('users').doc('HnH5TeCU1lUjeTqAYJ34ycjt78w22').get().then(function(doc) {
console.log(doc.data().createdAt.toDate());
}
También intenté agregar esto a mi declaración de mapa pero recibo un error que dice que user.get no es una función.
{user.get().then(function(doc) {
console.log(doc.data().createdAt.toDate());}
)}
Genera el mismo mensaje de error que el anterior.
PRÓXIMO INTENTO
Una cosa extraña que surgió al tratar de encontrar una manera de registrar una fecha en Firestore que me permita leerla de nuevo, es que cuando cambio mi controlador de envío en una forma para usar esta formulación:
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();
};
Eso funciona para registrar una fecha en la base de datos.
La forma de la entrada del almacén de incendios se ve así:
Estoy tratando de mostrar una fecha en este componente:
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);
Cuando intento leerlo de nuevo, usando:
{item.email}
El mensaje de error dice:
Error: Los objetos no son válidos como React child (encontrado: Timestamp (segundos = 1576363035, nanosegundos = 52000000)). Si desea representar una colección de elementos secundarios, utilice una matriz en su lugar. en Elemento (en UserIndex.jsx: 74)
Cuando intento usar cada uno de estos intentos:
{item.createdAt}
{item.createdAt.toDate()}
{item.createdAt.toDate().toISOString()}
Me sale un error que dice:
TypeError: no se puede leer la propiedad 'toDate' de undefined
Basado en la capacidad de volver a leer las entradas registradas en el mismo documento en otros campos, espero que cualquiera de estos funcione para producir resultados, incluso si no está formateado de la manera que quiero. Eso no pasa.
PRÓXIMO INTENTO
Tomando el ejemplo de Waelmas, traté de seguir las instrucciones, pero el primer paso es no obtener la misma respuesta. Cuando Walemas obtiene un resultado basado en la extensión .toDate (), aparece un error que dice que toDate () no es una función.
De acuerdo con la documentación de Firebase, probé:
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());
}})
Esto produce una serie de errores con la sintaxis y no puedo encontrar una forma de evitarlos.
PRÓXIMO INTENTO
Luego intenté hacer un nuevo formulario para ver si podía explorar esto sin el aspecto de autenticación del formulario de los usuarios.
Tengo un formulario que toma entrada como:
this.props.firebase.db.collection("insights").add({
title: title,
text: text,
// createdAt1: new Date(),
createdAt: this.props.firebase.fieldValue.serverTimestamp()
})
Donde en el formulario anterior, el nuevo intento de Date () funcionó para registrar una fecha en la base de datos, en este ejemplo, ambos campos para createdAt y createdAt1 generan la misma entrada de la base de datos:
<div>{item.createdAt.toDate()}</div>
<div>{item.createdAt.toDate()}</div>
Cuando trato de generar el valor de las fechas, el primero genera un error que dice:
Los objetos no son válidos como React child (encontrado: dom 15 dic 2019 21:33:32 GMT + 1100 (hora de verano del este de Australia)). Si pretendía representar una colección de elementos secundarios, utilice una matriz en su lugar
El segundo genera el error que dice:
TypeError: no se puede leer la propiedad 'toDate' de undefined
Estoy atrapado en ideas sobre qué probar a continuación.
Vi esta publicación que sugiere que lo siguiente podría hacer algo útil:
{item.createdAt1.Date.valueOf()}
No lo hace. Presenta un error que dice:
TypeError: no se puede leer la propiedad 'Fecha' de indefinido
Esta publicación parece tener los mismos problemas que yo, pero no explica cómo lograron mostrar el valor de la fecha que almacenaron.
Esta publicación parece estar atascada en el mensaje de error de la matriz, pero parece haber descubierto cómo mostrar una fecha usando createdAt.toDate ()
Cuando obtiene marcas de tiempo de Firestore, son del siguiente tipo:
Para convertir esto en una marca de tiempo normal, puede usar la función .toDate ().
Por ejemplo, para un documento como el siguiente:
Podemos usar algo como:
y la salida será como:
Ahora, para procesar aún más esa marca de tiempo, puede convertirla en una cadena y usar expresiones regulares para modificarla según sus necesidades.
Por ejemplo: (estoy usando Node.js aquí)
Te dará una salida como esta:
fuente
Así que firestore almacena las fechas como un objeto con segundos y nanosegundos. Si desea la hora en que se creó el usuario, debe hacer referencia
user.createdAt.nanoseconds
. Esto devuelve una marca de tiempo de Unix.¿Cómo desea mostrar la fecha en su aplicación? Si desea obtener un objeto de fecha, puede pasar la marca de tiempo a un constructor de fecha de esta manera
new Date(user.createdAt.nanoseconds)
. Personalmente, me gusta usar la biblioteca de fecha-fns para manejar el tiempo.fuente
user.createdAt && new Date(user.createdAt.nanoseconds)
. Date-fns no ayudará con este problema, que solo es una biblioteca útil para mostrar la fecha una vez que la tiene.firestore.FieldValue.serverTimestamp()
Cómo enviar la fecha a Firestore:
Cómo leerlo de nuevo:
Básicamente, cuando
createdAt.toDate()
obtienes un objeto JS Date.Lo uso así todo el tiempo!
De: https://cloud.google.com/firestore/docs/manage-data/add-data
Esto creará datos basados en la fecha del sistema del usuario. Si necesita asegurarse de que todo se almacenará cronológicamente (sin errores de fechas incorrectas del sistema establecidas por su sistema de usuarios) en su base de datos, debe usar una marca de tiempo del servidor. La fecha se establecerá utilizando su sistema de fecha interno Firestore DB.
fuente
Con una ID de documento de un usuario que tenga
createdAt
establecida la propiedad, intente lo siguiente:Es importante llamar al
.data()
método antes de acceder a las propiedades del documento.Tenga en cuenta que si accede
docRef.data().createdAt.toDate()
a un usuario para el quecreatedAt
no está establecida la propiedad, obtendráTypeError: Cannot read property 'toDate' of undefined
Entonces, en caso de que tenga algún usuario en su colección que no tenga ninguna
createdAt
propiedad definida. Debe implementar una lógica para verificar si el usuario tiene lacreatedAt
propiedad antes de obtenerla. Puedes hacer algo como esto:fuente
En el pasado, he encontrado problemas con las propiedades de los objetos anidados que no se representan correctamente en las listas donde
item.someProp
se considera un objeto, peroitem.someProp.someSubProp
no se resuelven con el valor desomeSubProp
initem.someProp
.Entonces, para evitar el problema, ¿por qué no evaluar Timestamp en un objeto de fecha simple (o el formato de visualización deseado) al crear el objeto de usuario?
fuente
DocumentSnapshot#data()
yDocumentSnapshot#get()
aceptar un objeto que especifica cómo manejar losFieldValue.serverTimestamp()
valores aún no finalizados . Por defecto, un aún no finalizado simplemente será nulo. El uso{ serverTimestamps: "estimate"}
cambiará estos valores nulos a una estimación.