Estou tentando descobrir como exibir um carimbo de data / hora do firestore em um aplicativo de reação.
Eu tenho um documento do firestore com um campo chamado createdAt.
Estou tentando incluí-lo em uma lista de saída (extraindo os bits relevantes aqui para que você não precise ler toda a 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()}
O único atributo que não será renderizado é a data.
Cada uma das tentativas acima gera um erro que diz:
TypeError: Não é possível ler a propriedade 'toDate' de undefined
Eu já vi esse post , e este post e este post , e este post e outros como eles, o que sugere que toDate () deve funcionar. Mas - esta extensão gera um erro para mim - inclusive quando tento a extensão toString.
Eu sei que ele sabe que há algo no firestore porque, quando tento user.createdAt, recebo um erro ao dizer que ele encontrou um objeto com segundos nele.
Tomando o exemplo de Waelmas abaixo, tentei registrar a saída do campo como:
this.db.collection('users').doc('HnH5TeCU1lUjeTqAYJ34ycjt78w22').get().then(function(doc) {
console.log(doc.data().createdAt.toDate());
}
Também tentei adicionar isso à minha declaração de mapa, mas obtive um erro que diz que user.get não é uma função.
{user.get().then(function(doc) {
console.log(doc.data().createdAt.toDate());}
)}
Ele gera a mesma mensagem de erro acima.
PRÓXIMA TENTATIVA
Uma coisa estranha que surgiu ao tentar encontrar uma maneira de registrar uma data no Firestore que me permita lê-la novamente é que, quando altero meu manipulador de envio de um formulário para usar esta formulação:
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();
};
Isso funciona para registrar uma data no banco de dados.
A forma da entrada do firestore é semelhante a esta:
Estou tentando exibir uma data neste 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);
Quando tento lê-lo novamente - usando:
{item.email}
A mensagem de erro diz:
Erro: Os objetos não são válidos como um filho do React (encontrado: Registro de data e hora (segundos = 1576363035, nanossegundos = 52000000)). Se você pretendia render uma coleção de filhos, use uma matriz. no item (em UserIndex.jsx: 74)
Quando tento usar cada uma dessas tentativas:
{item.createdAt}
{item.createdAt.toDate()}
{item.createdAt.toDate().toISOString()}
Eu recebo um erro que diz:
TypeError: Não é possível ler a propriedade 'toDate' de undefined
Com base na capacidade de ler novamente as entradas registradas no mesmo documento em outros campos, espero que alguma delas funcione para produzir saída, mesmo que não esteja formatada da maneira que desejo. Isso não acontece.
PRÓXIMA TENTATIVA
Tomando o exemplo de Waelmas, tentei seguir as instruções, mas onde não estamos obtendo a mesma resposta está no primeiro passo. Onde Walemas obtém uma saída com base na extensão .toDate (), recebo um erro dizendo que toDate () não é uma função.
Consistente com a documentação do Firebase, tentei:
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());
}}))
Isso produz uma série de erros com a sintaxe e não consigo encontrar uma maneira de contorná-los.
PRÓXIMA TENTATIVA
Tentei criar um novo formulário para ver se eu poderia explorar isso sem o aspecto de autenticação do formulário de usuários.
Eu tenho um formulário que recebe entrada como:
this.props.firebase.db.collection("insights").add({
title: title,
text: text,
// createdAt1: new Date(),
createdAt: this.props.firebase.fieldValue.serverTimestamp()
})
Onde no formulário anterior, a nova tentativa Date () trabalhou para registrar uma data no banco de dados; neste exemplo, os dois campos para createdAt e createdAt1 geram a mesma entrada do banco de dados:
<div>{item.createdAt.toDate()}</div>
<div>{item.createdAt.toDate()}</div>
Quando tento gerar o valor das datas, a primeira gera um erro que diz:
Os objetos não são válidos como um filho do React (encontrado: dom 15/12/2019 21:33:32 GMT + 1100 (horário de verão do leste da Austrália)). Se você pretendia render uma coleção de filhos, use uma matriz
O segundo gera o erro dizendo:
TypeError: Não é possível ler a propriedade 'toDate' de undefined
Estou preso a idéias sobre o que tentar a seguir.
Vi este post que sugere que o seguinte pode fazer algo útil:
{item.createdAt1.Date.valueOf()}
Não faz. Ele gera um erro que diz:
TypeError: Não é possível ler a propriedade 'Date' de undefined
Esta postagem parece estar tendo o mesmo problema que eu, mas não explica como eles conseguiram exibir o valor da data que armazenaram.
Esta postagem parece estar travando na mensagem de erro da matriz, mas parece ter descoberto como exibir uma data usando createdAt.toDate ()
Quando você obtém carimbos de data e hora do Firestore, eles são do seguinte tipo:
Para converter isso em um carimbo de data / hora normal, você pode usar a função .toDate ().
Por exemplo, para um documento como o seguinte:
Podemos usar algo como:
e a saída será como:
Agora, para processar ainda mais esse carimbo de data e hora, você pode convertê-lo em uma sequência e usar o regex para modificá-lo de acordo com suas necessidades.
Por exemplo: (estou usando o Node.js aqui)
Fornecerá uma saída como esta:
fonte
Portanto, o firestore armazena datas como um objeto com segundos e nanossegundos. Se você quiser a hora em que o usuário foi criado, faça referência
user.createdAt.nanoseconds
. Isso retorna um timestamp unix.Como você deseja exibir a data no seu aplicativo? Se você deseja obter um objeto de data, pode passar o registro de data e hora para um construtor de datas como esse
new Date(user.createdAt.nanoseconds)
. Pessoalmente, gosto de usar a biblioteca date-fns para lidar com o tempo.fonte
user.createdAt && new Date(user.createdAt.nanoseconds)
. Date-fns não vai ajudar com esse problema, que é apenas uma biblioteca útil para exibir a data depois que você a tiver.firestore.FieldValue.serverTimestamp()
Como enviar a data para o Firestore:
Como ler de volta:
Basicamente, quando você
createdAt.toDate()
obtém um objeto JS Date.Eu uso assim o tempo todo!
De: https://cloud.google.com/firestore/docs/manage-data/add-data
Isso criará dados com base na data do sistema do usuário. Se você precisar ter certeza de que tudo será armazenado cronologicamente (sem erros de datas erradas do sistema definidas pelo sistema do usuário) no seu banco de dados, use um carimbo de data / hora do servidor. A data será definida usando o sistema de datas interno do Firestore DB.
fonte
Com uma identificação de documento de um usuário que possui a
createdAt
propriedade definida, tente o seguinte:É importante chamar o
.data()
método antes de acessar as propriedades do documentoObserve que, se você acessar
docRef.data().createdAt.toDate()
um usuário para o qual acreatedAt
propriedade não está definida, você receberáTypeError: Cannot read property 'toDate' of undefined
Portanto, caso você tenha algum usuário em sua coleção que não possua
createdAt
propriedade definida. Você deve implementar uma lógica para verificar se o usuário possui acreatedAt
propriedade antes de obtê-la. Você pode fazer algo assim:fonte
Encontrei problemas no passado com propriedades de objetos aninhados que não eram renderizadas corretamente em listas onde
item.someProp
é considerado um objeto, masitem.someProp.someSubProp
não são resolvidas com o valor desomeSubProp
initem.someProp
.Portanto, para contornar o problema, por que não avaliar o carimbo de data / hora como um objeto de data simples (ou o formato de exibição desejado) ao criar o objeto de usuário?
fonte
DocumentSnapshot#data()
eDocumentSnapshot#get()
aceitar um objeto que especifica como manipularFieldValue.serverTimestamp()
valores ainda não finalizados . Por padrão, um ainda não finalizado será simplesmente nulo. O uso{ serverTimestamps: "estimate"}
alterará esses valores nulos para uma estimativa.