Я пытаюсь выяснить, как отобразить метку времени firestore в приложении реагирования.
У меня есть документ пожарного магазина с полем, созданным с именем.
Я пытаюсь включить его в список выходных данных (извлекая соответствующие биты, чтобы вам не приходилось читать весь список полей).
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()}
Единственный атрибут, который не будет отображаться - это дата.
Каждая из вышеуказанных попыток генерирует ошибку, которая говорит:
TypeError: Невозможно прочитать свойство 'toDate' из неопределенного
Я видел этот пост и этот пост и этот пост и этот пост и иже с ними, которые предполагают , что Todate () должен работать. Но - это расширение выдает ошибку для меня - в том числе, когда я пробую расширение toString.
Я знаю, он знает, что в firestore что-то есть, потому что, когда я пытаюсь использовать user.createdAt, я получаю сообщение об ошибке, в котором говорится, что он нашел объект с секундами в нем.
Взяв пример из Waelmas ниже, я попытался записать вывод поля как:
this.db.collection('users').doc('HnH5TeCU1lUjeTqAYJ34ycjt78w22').get().then(function(doc) {
console.log(doc.data().createdAt.toDate());
}
Я также попытался добавить это в свой оператор map, но получил ошибку, в которой говорится, что user.get не является функцией.
{user.get().then(function(doc) {
console.log(doc.data().createdAt.toDate());}
)}
Он генерирует то же сообщение об ошибке, что и выше.
СЛЕДУЮЩАЯ ПОПЫТКА
Одна странная вещь, которая возникла при попытке найти способ записи даты в Firestore, которая позволяет мне затем прочитать ее, заключается в том, что когда я меняю свой обработчик отправки в одной форме, чтобы использовать эту формулировку:
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();
};
Это работает, чтобы записать дату в базе данных.
Форма входа в пожарный магазин выглядит так:
Я пытаюсь отобразить дату в этом компоненте:
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);
Когда я пытаюсь прочитать это обратно - используя:
{} Item.email
Сообщение об ошибке гласит:
Ошибка: объекты недопустимы как дочерний элемент React (найдено: метка времени (секунд = 1576363035, наносекунд = 52000000)). Если вы хотите отобразить коллекцию дочерних элементов, используйте вместо этого массив. в элементе (в UserIndex.jsx: 74)
Когда я пытаюсь использовать каждую из этих попыток:
{item.createdAt}
{item.createdAt.toDate()}
{item.createdAt.toDate().toISOString()}
Я получаю сообщение об ошибке:
TypeError: Невозможно прочитать свойство 'toDate' из неопределенного
Основываясь на способности читать записи, записанные в том же документе в других полях, я ожидаю, что любое из них сработает, чтобы вывести выходные данные, даже если они не отформатированы так, как я хочу. Этого не происходит.
СЛЕДУЮЩАЯ ПОПЫТКА
Принимая пример Вельмаса, я пытался следовать инструкциям, но там, где мы не получаем тот же ответ, это первый шаг. Когда Walemas получает вывод, основанный на расширении .toDate (), я получаю сообщение о том, что toDate () не является функцией.
В соответствии с документацией Firebase я попытался:
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());
}})
Это приводит к ряду ошибок с синтаксисом, и я не могу найти способ их обойти.
СЛЕДУЮЩАЯ ПОПЫТКА
Затем я попытался создать новую форму, чтобы посмотреть, смогу ли я изучить это без аспекта аутентификации формы пользователей.
У меня есть форма, которая принимает входные данные как:
this.props.firebase.db.collection("insights").add({
title: title,
text: text,
// createdAt1: new Date(),
createdAt: this.props.firebase.fieldValue.serverTimestamp()
})
Если в предыдущей форме новая попытка Date () работала для записи даты в базу данных, то в этом примере оба поля для createAt и selectedAt1 генерируют одну и ту же запись базы данных:
<div>{item.createdAt.toDate()}</div>
<div>{item.createdAt.toDate()}</div>
Когда я пытаюсь вывести значение дат, первое выдает ошибку, которая говорит:
Объекты недопустимы в качестве дочерних элементов React (найдено: вс 15 декабря 2019 21:33:32 GMT + 1100 (по восточному летнему времени Австралии)). Если вы хотите отобразить коллекцию дочерних элементов, используйте вместо этого массив
Второй генерирует ошибку, говоря:
TypeError: Невозможно прочитать свойство 'toDate' из неопределенного
Я застрял на идеи о том, что попробовать дальше.
Я видел этот пост, который предполагает, что следующее может сделать что-то полезное:
{item.createdAt1.Date.valueOf()}
Это не так. Это делает ошибку, которая говорит:
TypeError: Невозможно прочитать свойство 'Date' из неопределенного
Кажется, у этого поста такая же проблема, как и у меня, но в нем не рассматривается, как им удалось отобразить значение даты, которое они сохранили.
Это сообщение, похоже, застревает в сообщении об ошибке массива, но, похоже, выяснило, как отображать дату с помощью createAt.toDate ()
Когда вы получаете метки времени из Firestore, они имеют следующий тип:
Чтобы преобразовать это в обычную метку времени, вы можете использовать функцию .toDate ().
Например, для документа, подобного следующему:
Мы можем использовать что-то вроде:
и вывод будет таким:
Теперь для дальнейшей обработки этой отметки времени вы можете преобразовать ее в строку и использовать регулярные выражения для ее изменения в соответствии с вашими потребностями.
Например: (я использую Node.js здесь)
Даст вам вывод, как это:
источник
Таким образом, FireStore хранит даты как объект с секундами и наносекундами. Если вы хотите время, когда пользователь был создан, вы бы ссылались
user.createdAt.nanoseconds
. Это возвращает метку времени Unix.Как вы хотите отображать дату в вашем приложении? Если вы хотите получить объект даты, вы можете передать метку времени в конструктор даты следующим образом
new Date(user.createdAt.nanoseconds)
. Лично мне нравится использовать библиотеку date-fns для обработки времени.источник
user.createdAt && new Date(user.createdAt.nanoseconds)
. Date-fns не поможет с этой проблемой, это просто удобная библиотека для отображения даты, когда она у вас есть.firestore.FieldValue.serverTimestamp()
Как отправить дату в Firestore:
Как читать это обратно:
По сути, когда вы
createdAt.toDate()
получаете объект JS Date.Я использую это все время!
От: https://cloud.google.com/firestore/docs/manage-data/add-data
Это создаст данные на основе системной даты пользователя. Если вы хотите быть уверены, что все будет храниться в вашей БД в хронологическом порядке (без каких-либо ошибок в неправильных системных датах, установленных вашей системой пользователей), вам следует использовать временную метку сервера. Дата будет установлена с использованием вашей внутренней системы дат Firestore DB.
источник
С идентификатором документа пользователя, у которого установлено
createdAt
свойство, попробуйте следующее:Мне важно вызвать
.data()
метод перед доступом к свойствам документа.Обратите внимание, что если вы обращаетесь
docRef.data().createdAt.toDate()
к пользователю, для которогоcreatedAt
свойства не установлены, вы получитеTypeError: Cannot read property 'toDate' of undefined
Так что в случае, если у вас есть пользователь в вашей коллекции, у которого не
createdAt
определено свойство. Вы должны реализовать логику, чтобы проверить, есть ли у пользователяcreatedAt
свойство перед его получением. Вы можете сделать что-то вроде этого:источник
В прошлом я сталкивался с проблемами со свойствами вложенных объектов, которые не отображаются должным образом в списках, где
item.someProp
он считается объектом, ноitem.someProp.someSubProp
не будет разрешен со значениемsomeSubProp
initem.someProp
.Итак, чтобы обойти эту проблему, почему бы не оценить Timestamp для простого объекта даты (или желаемого формата отображения) при создании пользовательского объекта?
источник
DocumentSnapshot#data()
иDocumentSnapshot#get()
принимают объект, который указывает, как обрабатывать еще не завершенныеFieldValue.serverTimestamp()
значения. По умолчанию еще не завершенный будет нулевым. Использование{ serverTimestamps: "estimate"}
изменит эти нулевые значения на оценку.