React - tampilkan cap waktu firestore

10

Saya mencoba mencari cara menampilkan cap waktu firestore di aplikasi reaksi.

Saya memiliki dokumen firestore dengan bidang bernama CreatedAt.

Saya mencoba memasukkannya dalam daftar output (mengekstraksi bit yang relevan di sini sehingga Anda tidak perlu membaca seluruh daftar bidang).

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()}

Satu-satunya atribut yang tidak akan menyajikan adalah tanggal.

Setiap upaya di atas menghasilkan kesalahan yang mengatakan:

TypeError: Tidak dapat membaca properti 'toDate' dari undefined

Saya telah melihat posting ini , dan posting ini dan posting ini , dan posting ini dan lain-lain seperti mereka, yang menunjukkan todate bahwa () harus bekerja. Tetapi - ekstensi ini menimbulkan kesalahan bagi saya - termasuk ketika saya mencoba ekstensi toString.

Saya tahu ia tahu ada sesuatu di firestore karena ketika saya mencoba user.createdAt, saya mendapatkan pesan kesalahan ketika menemukan objek dengan detik di dalamnya.

Mengambil contoh dari Waelmas di bawah ini, saya mencoba mencatat output dari bidang sebagai:

this.db.collection('users').doc('HnH5TeCU1lUjeTqAYJ34ycjt78w22').get().then(function(doc) {
  console.log(doc.data().createdAt.toDate());

}

Saya juga mencoba menambahkan ini ke pernyataan peta saya tetapi mendapatkan kesalahan yang mengatakan user.get bukan fungsi.

{user.get().then(function(doc) {
                    console.log(doc.data().createdAt.toDate());}
                  )}

Ini menghasilkan pesan kesalahan yang sama seperti di atas.

masukkan deskripsi gambar di sini

PERIKSAAN BERIKUTNYA

Satu hal aneh yang muncul ketika mencoba menemukan cara untuk merekam tanggal di Firestore yang memungkinkan saya untuk kemudian membacanya kembali, adalah ketika saya mengubah handler kirim saya dalam satu bentuk untuk menggunakan formulasi ini:

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();
    };

Itu berfungsi untuk merekam tanggal dalam database.

Bentuk entri firestore terlihat seperti ini:

masukkan deskripsi gambar di sini

Saya mencoba menampilkan tanggal di komponen ini:

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);

Ketika saya mencoba membacanya kembali - menggunakan:

{item.email}

Pesan kesalahan berbunyi:

Kesalahan: Objek tidak valid sebagai anak Bereaksi (ditemukan: Stempel waktu (detik = 1576363035, nanodetik = 52000000)). Jika Anda bermaksud membuat koleksi anak-anak, gunakan array. dalam Item (di UserIndex.jsx: 74)

Ketika saya mencoba menggunakan setiap upaya ini:

{item.createdAt}
{item.createdAt.toDate()}
{item.createdAt.toDate().toISOString()}

Saya mendapatkan kesalahan yang mengatakan:

TypeError: Tidak dapat membaca properti 'toDate' dari undefined

Berdasarkan kemampuan untuk membaca kembali entri yang masuk dalam dokumen yang sama di bidang lain, saya berharap semua ini berfungsi untuk menghasilkan keluaran-bahkan jika tidak diformat seperti yang saya inginkan. Itu tidak terjadi.

PERIKSAAN BERIKUTNYA

Mengambil contoh Waelmas, saya mencoba mengikuti instruksi, tetapi di mana kita tidak mendapatkan respons yang sama adalah pada langkah pertama. Di mana Walemas mendapatkan output berdasarkan ekstensi .toDate (), saya mendapatkan pesan kesalahan mengatakan toDate () bukan fungsi.

Konsisten dengan dokumentasi Firebase, saya mencoba:

    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());

}})

Ini menghasilkan serangkaian kesalahan dengan sintaks dan saya tidak dapat menemukan jalan keluarnya.

PERIKSAAN BERIKUTNYA

Saya kemudian mencoba membuat formulir baru untuk melihat apakah saya dapat menjelajahi ini tanpa aspek otentikasi dari formulir pengguna.

Saya memiliki formulir yang menerima input sebagai:

this.props.firebase.db.collection("insights").add({
            title: title,
            text: text,
            // createdAt1: new Date(),
            createdAt: this.props.firebase.fieldValue.serverTimestamp()
        })

Di mana dalam formulir sebelumnya, upaya Date () yang baru berfungsi untuk merekam tanggal dalam database, dalam contoh ini kedua bidang untuk CreatedAt dan CreatedAt1 menghasilkan entri basis data yang sama:

masukkan deskripsi gambar di sini

<div>{item.createdAt.toDate()}</div>
                    <div>{item.createdAt.toDate()}</div>

Saat saya mencoba menampilkan nilai tanggal, yang pertama menghasilkan kesalahan yang mengatakan:

Objek tidak valid sebagai anak Bereaksi (ditemukan: Minggu 15 Des 2019 21:33:32 GMT + 1100 (Waktu Siang Timur Australia)). Jika Anda bermaksud membuat koleksi anak-anak, gunakan array

Yang kedua menghasilkan kesalahan dengan mengatakan:

TypeError: Tidak dapat membaca properti 'toDate' dari undefined

Saya tidak dapat menemukan ide tentang apa yang harus dicoba selanjutnya.

Saya melihat posting ini yang menunjukkan bahwa hal berikut mungkin melakukan sesuatu yang bermanfaat:

                {item.createdAt1.Date.valueOf()}

Tidak. Itu membuat kesalahan yang mengatakan:

TypeError: Tidak dapat membaca properti 'Tanggal' yang tidak ditentukan

Posting ini tampaknya memiliki masalah yang sama dengan saya, tetapi tidak membahas bagaimana mereka berhasil menampilkan nilai tanggal yang mereka simpan.

Posting ini tampaknya terjebak pada pesan kesalahan array, tetapi tampaknya telah menemukan cara untuk menampilkan tanggal menggunakan CreatedAt.toDate ()

Mel
sumber

Jawaban:

1

Setelah beberapa diskusi, kami menemukan bahwa perangko waktu pada objek pengguna OP dapat dirender seperti:

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} 
                    {new Date(user.createdAt.seconds * 1000).toLocaleDateString("en-US")}

Saya menciptakan kembali contoh Anda dalam proyek Dummy React, dan menerima kesalahan yang sama seperti yang diharapkan.

Kesalahan: Objek tidak valid sebagai anak Bereaksi

Saya bisa membuat ini di-render dengan benar dengan metode berikut, yang juga bisa digunakan untuk Anda:

{new Date(user.createdAt._seconds * 1000).toLocaleDateString("en-US")}

Yang, untuk stempel waktu sampel saya, diterjemahkan sebagai:

12/30/2019


Pastikan Anda menggunakan stempel waktu yang disimpan ke Firestore sebagai:

createdAt: this.props.firebase.Timestamp.fromDate(new Date())

Catatan: Ini dengan asumsi bahwa instance Anda firebase.firestore()adalah pada this.props.firebase. Dalam contoh lain Anda menggunakan this.props.firebase, tetapi metode tersebut terlihat seperti metode pembantu yang Anda buat sendiri.

Ketika nilai ini diambil, itu akan menjadi objek dengan dua properti - _secondsdan _nanoseconds.

Pastikan untuk memasukkan garis bawah. Jika Anda menggunakannya createdAt.secondstidak akan berhasil, itu harus createdAt._seconds.


Hal-hal lain yang saya coba:

user.createdAt.toDate()melempar toDate() is not a function.

user.createdAt melempar Error: Objects are not valid as a React child

new Date(user.createdAt._nanoseconds) menjadikan tanggal yang salah

Michael Rodriguez
sumber
Hai - terima kasih atas sarannya. Saya mencoba ini dan mendapatkan kesalahan yang mengatakan: TypeError: Tidak dapat membaca properti 'Timestamp' yang tidak terdefinisi
Mel
Saya juga mencoba: CreatedAt: firebase.firestore.fieldValue.serverTimestamp (). FromDate (Date baru ()), yang mengembalikan kesalahan yang mengatakan: TypeError: Tidak dapat membaca properti 'fieldValue' dari undefined
Mel
Meskipun ini tidak berhasil untuk saya, saya tertarik untuk memahami bagaimana Anda berpikir untuk mencoba format yang Anda gunakan. Tidak seperti yang ditunjukkan dalam dokumentasi. Jika saya dapat belajar bagaimana Anda menemukan sesuatu yang bekerja untuk Anda, mungkin saya dapat menemukan cara yang bekerja untuk saya (saya tidak mengerti mengapa itu bukan hal yang sama untuk semua orang - tetapi saya perlu ide baru untuk mencoba sesuatu ). Sekali lagi terima kasih telah mencoba membantu.
Mel
Apa yang bisa saya lakukan adalah menyimpan tanggal (seperti yang ditunjukkan di atas) menggunakan: CreatedAt: this.props.firebase.fieldValue.serverTimestamp (),
Mel
1
Mari kita lanjutkan diskusi ini dalam obrolan .
Michael Rodriguez
5

Ketika Anda mendapatkan cap waktu dari Firestore, mereka berasal dari tipe berikut:

masukkan deskripsi gambar di sini

Untuk mengonversikan ini menjadi cap waktu normal, Anda dapat menggunakan fungsi .toDate ().

Misalnya, untuk dokumen seperti berikut:

masukkan deskripsi gambar di sini

Kita dapat menggunakan sesuatu seperti:

db.collection('[COLLECTION]').doc('[DOCUMENT]').get().then(function(doc) {
  console.log(doc.data().[FIELD].toDate());
});

dan hasilnya akan seperti:

2019-12-16T16:27:33.031Z

Sekarang untuk memproses stempel waktu lebih lanjut, Anda dapat mengubahnya menjadi string dan menggunakan regex untuk memodifikasinya sesuai dengan kebutuhan Anda.

Misalnya: (Saya menggunakan Node.js di sini)

db.collection('[COLLECTION]').doc('[DOCUMENT]').get().then(function(doc) {
  var stringified = doc.data().[FIELD].toDate().toISOString();
  //console.log(stringified);
  var split1 = stringified.split('T');
  var date = split1[0].replace(/\-/g, ' ');
  console.log(date);
  var time = split1[1].split('.');
  console.log(time[0]);
});

Akan memberikan Anda output seperti ini:

masukkan deskripsi gambar di sini

Waelmas
sumber
Terima kasih untuk contohnya Saya memiliki struktur yang sama dalam upaya saya. Ini berfungsi untuk mengembalikan semua nilai string dalam dokumen tetapi bukan tanggal. Sebaliknya, itu menghasilkan kesalahan dengan pesan yang saya posting di atas. Itu tidak masuk akal. Saya mencoba menambahkan ekstensi toISOString () tetapi tidak mengubah pesan kesalahan (yang seharusnya hanya memformat)
Mel
Bisakah Anda mencatat nilai cap waktu di konsol? Hanya untuk mengonfirmasi itu adalah jenis cap waktu Firestore yang benar. @Mel
Waelmas
Tidak - log konsol tidak berfungsi - menghasilkan kesalahan juga - tetapi tanggal direkam dalam bidang CreatedAt di tabel - sekarang saya hanya mencoba untuk membacanya kembali. Saya membuat posting yang menjelaskan bagaimana saya mendapatkan tanggal untuk dicatat (tidak sesuai dengan dokumentasi firebase) di sini: stackoverflow.com/questions/59257755/…
Mel
Karena Anda mengikuti pendekatan yang berbeda dari yang direkomendasikan oleh dokumen resmi, saya tidak yakin apa yang sebenarnya salah. Sepertinya cara Anda membuat dan mendorong stempel waktu di tempat pertama entah bagaimana salah. Ketika Anda menyimpan stempel waktu ke Firestore, ia harus menjadi objek format yang telah saya sebutkan di awal jawaban saya. Dengan cara ini akan dikenali sebagai cap waktu yang valid yang kemudian dapat digunakan dengan .toDate (). Firestore.Timestamp.now () akan memberi Anda cap waktu format yang benar untuk memeriksanya. @Mel
Waelmas
Saya mencoba mengikuti dokumentasi resmi untuk membuat cap waktu. Saya tidak bisa membuatnya bekerja. Saya menemukan cara alternatif untuk merekam tanggal dan sekarang tidak dapat membaca kembali hasilnya! Sangat membuat frustrasi. Terima kasih sudah mencoba.
Mel
2

Jadi firestore menyimpan kurma sebagai objek dengan detik dan nanodetik. Jika Anda ingin waktu pengguna dibuat maka Anda akan referensi user.createdAt.nanoseconds. Ini mengembalikan cap waktu unix.

Bagaimana Anda ingin menampilkan tanggal di aplikasi Anda? Jika Anda ingin mendapatkan objek tanggal maka Anda dapat melewati timestamp ke konstruktor tanggal seperti itu new Date(user.createdAt.nanoseconds). Secara pribadi saya menikmati menggunakan perpustakaan tanggal-fns untuk menangani waktu.

Josh Pittman
sumber
Terima kasih - saya mencoba saran ini. Ini mengembalikan kesalahan yang mengatakan: TypeError: Tidak dapat membaca properti 'nanoseconds' dari undefined. Saya akan melihat perpustakaan yang Anda sarankan sekarang
Mel
Bisakah Anda login, buat, dan bagikan, silakan. Mengingat sifat async data, Anda mungkin hanya perlu mengembalikannya seperti itu user.createdAt && new Date(user.createdAt.nanoseconds). Date-fns tidak akan membantu dengan masalah ini, itu hanya pustaka praktis untuk menampilkan tanggal setelah Anda memilikinya.
Josh Pittman
CreatedAt mencatat daftar panjang menu dropdown. Saya tidak dapat menemukan satu yang berisi tanggal yang ditampilkan di lapangan di firestore. Bagian pertama adalah: createdAt: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" proto : FieldValueImpl konstruktor: ServerTimestampFieldValueImpl ƒ () misalnya: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" proto : FieldValueImpl konstruktor: ƒ ServerTimestampFieldValueImpl () misalnya: ServerTimestampFieldValueImpl {_methodName: " Argumen FieldValue.serverTimestamp "}: (...) pemanggil: (...)
Mel
Sepertinya Anda telah mendorong fungsi cap waktu ke database, bukan cap waktu yang sebenarnya. Bagaimana Anda mengatur cap waktu? firestore.FieldValue.serverTimestamp()
Josh Pittman
Entri yang ditampilkan di firestore adalah foto yang saya lampirkan. Ini adalah entri: this.props.firebase.fieldValue.serverTimestamp ()
Mel
2

Cara mengirim tanggal ke Firestore:

import firebase from 'firebase/app';

// ..........
// someObject is the object you're saving to your Firestore.

someObject.createdAt: firebase.firestore.Timestamp.fromDate(new Date())

Cara membacanya kembali:

function mapMonth(monthIndex) {
  const months = {
    0: 'jan',
    1: 'feb',
    2: 'mar',
    3: 'apr',
    4: 'may',
    5: 'jun',
    6: 'jul',
    7: 'aug',
    8: 'sep',
    9: 'oct',
    10: 'nov',
    11: 'dec'
  };
  return months[monthIndex];
}

// ..........
// Here you already read the object from Firestore and send its properties as props to this component.

return(
    <LS.PostDate_DIV>
      Published on {mapMonth(props.createdAt.toDate().getMonth()) + ' '}
      of {props.createdAt.toDate().getFullYear()}
    </LS.PostDate_DIV>
  );
}

Pada dasarnya ketika Anda melakukannya, createdAt.toDate()Anda mendapatkan objek Tanggal JS.

Saya menggunakannya seperti ini setiap saat!

Dari: https://cloud.google.com/firestore/docs/manage-data/add-data

masukkan deskripsi gambar di sini

Ini akan membuat data berdasarkan tanggal sistem pengguna. Jika Anda perlu memastikan bahwa semuanya akan disimpan secara kronologis (tanpa ada kesalahan tanggal sistem yang ditetapkan oleh sistem pengguna Anda) pada DB Anda, Anda harus menggunakan stempel waktu server. Tanggal akan ditetapkan menggunakan sistem tanggal internal DB Firestore Anda.

masukkan deskripsi gambar di sini

cbdeveloper
sumber
Terima kasih untuk ini, tetapi masalah yang saya coba atasi adalah bahwa saya tidak dapat menemukan cara untuk menampilkan tanggal yang tercatat dalam database. Saya terus mendapatkan kesalahan dari jenis yang saya bagikan.
Mel
2

Dengan ID dokumen Pengguna yang memiliki createdAtproperti yang disetel, coba yang berikut ini:

const docRef = db.collection("users").doc("[docID]");

docRef.get().then(function(docRef) {
  if (docRef.exists) {
     console.log("user created at:", docRef.data().createdAt.toDate());
  }
})

Saya tidak perlu memanggil .data()metode sebelum mengakses properti dokumen

Perhatikan bahwa jika Anda mengakses docRef.data().createdAt.toDate()pengguna yang createdAthaknya tidak ditetapkan, Anda akan mendapatkannyaTypeError: Cannot read property 'toDate' of undefined

Jadi jika Anda memiliki pengguna dalam koleksi Anda yang tidak memiliki createdAtproperti yang ditentukan. Anda harus menerapkan logika untuk memeriksa apakah pengguna memiliki createdAtproperti sebelum mendapatkannya. Anda dapat melakukan sesuatu seperti ini:

//This code gets all the users and logs it's creation date in the console
docRef.get().then(function(docRef) {
  if (docRef.exists && docRef.data().createdAt) {
      console.log("User created at:", docRef.data().createdAt.toDate());
  }
})
Jose V
sumber
Seperti yang Anda lihat di atas, saya menggunakan data () dalam permintaan saya untuk bidang dokumen. Jika tidak, bidang lainnya tidak akan ditampilkan. Masalah khusus adalah dengan cap waktu, yang tidak memberikan. Salah satu upaya yang saya lakukan, dan yang saya jelaskan di atas, termasuk upaya menggunakan ekstensi toDate (). Tidak berfungsi - untuk alasan yang disebutkan di atas. Terima kasih atas waktu Anda.
Mel
0

Saya pernah mengalami masalah di masa lalu dengan properti objek bersarang tidak merender dengan benar dalam daftar item.somePropyang dianggap objek, tetapi item.someProp.someSubProptidak akan diselesaikan dengan nilai someSubPropin item.someProp.

Jadi untuk mengatasi masalah ini, mengapa tidak mengevaluasi Timestamp ke objek tanggal polos (atau format tampilan yang diinginkan) saat membuat objek pengguna?

this.unsubscribe = this.props.firebase
  .users()
  .onSnapshot(snapshot => {
    let users = [];

    snapshot.forEach(doc =>
      let docData = doc.data();
      docData.createdAt = docData.createdAt.toDate();
      users.push({ ...docData, uid: doc.id }),
    );

    this.setState({
      users,
      loading: false,
    });
  });
samthecodingman
sumber
Juga perlu dicatat bahwa keduanya DocumentSnapshot#data()dan DocumentSnapshot#get()menerima objek yang menentukan cara menangani FieldValue.serverTimestamp()nilai yang belum selesai . Secara default, yang belum selesai hanya akan menjadi nol. Menggunakan { serverTimestamps: "estimate"}akan mengubah nilai-nilai nol ini ke taksiran.
samthecodingman
Hai - terima kasih atas sarannya. Saya ingin mencobanya tetapi saya tidak memahaminya - atau bagaimana saya bisa mencoba mengimplementasikannya. Apakah ada konvensi untuk prinsip-prinsip yang Anda terapkan dalam menghasilkan saran ini. Jika saya dapat menemukan literatur tentang pendekatan tersebut, saya akan mencoba mencari tahu bagaimana ide Anda bekerja sehingga saya dapat mencobanya dalam kode saya.
Mel
Saya tidak punya sumber daya khusus untuk itu, karena saya mengambilnya setelah melihat pertanyaan StackOverflow lainnya selama bertahun-tahun.
samthecodingman
Terima kasih telah berbagi. Saya akan membaca ini malam ini
Mel