70

I'm newbie to Firestore. Firestore docs says...

Important: Unlike "push IDs" in the Firebase Realtime Database, Cloud Firestore auto-generated IDs do not provide any automatic ordering. If you want to be able to order your documents by creation date, you should store a timestamp as a field in the documents.

Reference: https://firebase.google.com/docs/firestore/manage-data/add-data

So do I have to create key name as timestamp in document? Or created is suffice to fulfill above statement from Firestore documentation.

{
    "created": 1534183990,
    "modified": 1534183990,
    "timestamp":1534183990
}
Vicky Thakor
  • 3,847
  • 7
  • 42
  • 67

18 Answers18

72
firebase.firestore.FieldValue.serverTimestamp()

Whatever you want to call it is fine afaik. Then you can use orderByChild('created').

I also mostly use firebase.database.ServerValue.TIMESTAMP when setting time

ref.child(key).set({
  id: itemId,
  content: itemContent,
  user: uid,
  created: firebase.database.ServerValue.TIMESTAMP 
})
Saccarab
  • 1,399
  • 12
  • 25
  • 1
    Yes I'm using `FieldValue.serverTimestamp` only. But I want to make sure that its not mandatory to store key with name `timestamp` – Vicky Thakor Aug 14 '18 at 17:45
  • 1
    It should workout since you are providing the key name when you are calling orderBy. – Saccarab Aug 14 '18 at 17:49
  • 2
    Using firebase.database.ServerValue.TIMESTAMP in Firestore is not working: – Valeri Apr 12 '19 at 15:44
  • 1
    Just .sv: timestamp is set. – Valeri Apr 12 '19 at 15:44
  • 43
    in firestore to get the timestamp you should use `firebase.firestore.FieldValue.serverTimestamp()` instead of `firebase.database.ServerValue.TIMESTAMP` – Zvi Karp Oct 17 '19 at 23:08
  • `firebase.firestore.FieldValue.serverTimestamp()` actually looks correct on the web console backend!! the other one that @Saccarab suggested doesn't show up as an actual timestamp on the database – David T. Sep 14 '20 at 08:35
  • Yes, as noted, this answer **does not apply** to Firestore. This is what you want if you are using the **Firebase Realtime Database** – uɥƃnɐʌuop Mar 02 '21 at 20:25
  • "firebase" not found in "firebase.database.ServerValue.TIMESTAMP". Kindly suggest which package should I include to solve it. Thanks. – Kamlesh Jun 15 '21 at 14:03
  • In the version 9 use o import : `import { Timestamp } from '@angular/fire/firestore'` In the code put it like this `createdAt: Timestamp.fromDate(new Date())` – LuscaDev May 02 '23 at 19:47
54

Use firestore Timestamp class, firebase.firestore.Timestamp.now().

Since firebase.firestore.FieldValue.serverTimestamp() does not work with add method from firestore. Reference

johnson lai
  • 996
  • 1
  • 11
  • 15
  • 2
    Thanks! Not forget `const firebase = require('firebase-admin')` in top of index.js and dependency `firebase-admin` in package.json – Abner Escócio May 09 '20 at 06:10
  • Thanks this should be the top answer! – Saaransh Menon Aug 28 '20 at 21:27
  • When I try this, I get an error that says: "cannot read property 'now' of undefined". Do you know if this approach is still current? – Mel Apr 02 '21 at 22:28
  • `Timestamp.now()` will return the current browser time, which may be altered by user to work around your app time restrictions – FindOutIslamNow Jun 03 '21 at 04:06
  • "firebase" not found in "firebase.firestore.FieldValue.serverTimestamp()". Kindly suggest which package should I include to solve it. Thanks. – Kamlesh Jun 15 '21 at 14:05
  • Amazing! Thanks! – PhillipJacobs Apr 23 '22 at 12:23
  • @Kamlesh If you are using Firebase v9.x, you should `#import { serverTimestamp } from "firebase/firestore"` rather than trying to access `firebase.firestore.etc`. See https://stackoverflow.com/questions/69519447/how-to-get-server-timestamp-from-firebase-v9 – Aaron Campbell Jul 08 '22 at 02:54
11

REALTIME SERVER TIMESTAMP USING FIRESTORE

import firebase from "firebase/app";

const someFunctionToUploadProduct = () => {

       firebase.firestore().collection("products").add({
                name: name,
                price : price,
                color : color,
                weight :weight,
                size : size,
                createdAt : firebase.firestore.FieldValue.serverTimestamp()
            })
            .then(function(docRef) {
                console.log("Document written with ID: ", docRef.id);
            })
            .catch(function(error) {
                console.error("Error adding document: ", error);
            });

}

All you need is to import 'firebase' and then call firebase.firestore.FieldValue.serverTimestamp() wherever you need it. Be careful with the spelling though, its "serverTimestamp()". In this example it provides the timestamp value to 'createdAt' when uploading to the firestore's product's collection.

John Yepthomi
  • 472
  • 6
  • 13
  • This does not work: `Attempted import error: 'firebase/app' does not contain a default export (imported as 'firebase').` – Ben Mar 29 '22 at 07:25
  • 1
    @Ben If you are using Firebase v9.x, you should `#import { serverTimestamp } from "firebase/firestore"` rather than trying to access `firebase.firestore.etc`. See https://stackoverflow.com/questions/69519447/how-to-get-server-timestamp-from-firebase-v9 – Aaron Campbell Jul 08 '22 at 02:54
  • haven't been working with firebase for a long time now and you should be aware that firesbase does undergo changes which might mean a different import path. I think @AaronCampbell solution should help. – John Yepthomi Jul 08 '22 at 10:49
10

For Firestore

ref.doc(key).set({
  created: firebase.firestore.FieldValue.serverTimestamp()
})
Venkat Kotra
  • 10,413
  • 3
  • 49
  • 53
10

That's correct, like most database, Firestore doesn't store creation times. In order to sort objects by time:

Option 1: Create timestamp on client (correctness not guaranteed):

db.collection("messages").doc().set({
  ....
  createdAt: firebase.firestore.Timestamp.now()
})

The big caveat here is that Timestamp.now()uses the local machine time. Therefore, if this is run on a client machine, you have no guarantee the timestamp is accurate. If you're setting this on the server or if guaranteed order isn't so important, it might be fine.

Option 2: Use a timestamp sentinel:

db.collection("messages").doc().set({
  ....
  createdAt: firebase.firestore.FieldValue.serverTimestamp()
})

A timestamp sentinel is a token that tells the firestore server to set the time server side on first write.

If you read the sentinel before it is written (e.g., in a listener) it will be NULL unless you read the document like this:

doc.data({ serverTimestamps: 'estimate' })

Set up your query with something like this:

// quick and dirty way, but uses local machine time
const midnight = new Date(firebase.firestore.Timestamp.now().toDate().setHours(0, 0, 0, 0));

const todaysMessages = firebase
  .firestore()
  .collection(`users/${user.id}/messages`)
  .orderBy('createdAt', 'desc')
  .where('createdAt', '>=', midnight);

Note that this query uses the local machine time (Timestamp.now()). If it's really important that your app uses the correct time on the clients, you could utilize this feature of Firebase's Realtime Database:

const serverTimeOffset = (await firebase.database().ref('/.info/serverTimeOffset').once('value')).val();
const midnightServerMilliseconds = new Date(serverTimeOffset + Date.now()).setHours(0, 0, 0, 0);
const midnightServer = new Date(midnightServerMilliseconds);
uɥƃnɐʌuop
  • 14,022
  • 5
  • 58
  • 61
2

The documentation isn't suggesting the names of any of your fields. The part you're quoting is just saying two things:

  1. The automatically generated document IDs for Firestore don't have a natural time-based ordering like they did in Realtime Database.
  2. If you want time-based ordering, store a timestamp in the document, and use that to order your queries. (You can call it whatever you want.)
Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
2

This solution worked for me:

Firestore.instance.collection("collectionName").add({'created': Timestamp.now()});

The result in Cloud Firestore is: Cloud Firestore Result

Marcel
  • 173
  • 3
  • 8
  • 1
    This won't work because the system date-time could be changed by the user manually. OP wants the server DateTime instead of the local ones. – Akshay Jul 03 '20 at 09:31
1

Try this one for Swift 4 Timestamp(date: Date())

let docData: [String: Any] = [
"stringExample": "Hello world!",
"booleanExample": true,
"numberExample": 3.14159265,
"dateExample": Timestamp(Date()),
"arrayExample": [5, true, "hello"],
"nullExample": NSNull(),
"objectExample": [
    "a": 5,
    "b": [
        "nested": "foo"
    ]
]
]
db.collection("data").document("one").setData(docData) { err in
if let err = err {
    print("Error writing document: \(err)")
} else {
    print("Document successfully written!")
}
}
coders
  • 2,287
  • 1
  • 12
  • 20
1

The way it worked with me, is just taking the timestamp from the snapshot parameter snapshot.updateTime

exports.newUserCreated = functions.firestore.document('users/{userId}').onCreate(async (snapshot, context) => {
console.log('started!     v1.7');
const userID = context.params['userId'];

firestore.collection(`users/${userID}/lists`).add({
    'created_time': snapshot.updateTime,
    'name':'Products I ♥',
}).then(documentReference => {
    console.log("initial public list created");
    return null;
  }).catch(error => {
    console.error('Error creating initial list', error);
    process.exit(1);
});

});

Bishoy Hanna
  • 4,539
  • 1
  • 29
  • 31
1

According to the docs, you can "set a field in your document to a server timestamp which tracks when the server receives the update".

Example:

import { updateDoc, serverTimestamp } from "firebase/firestore";

const docRef = doc(db, 'objects', 'some-id');

// Update the timestamp field with the value from the server
const updateTimestamp = await updateDoc(docRef, {
    timestamp: serverTimestamp() // this does the trick!
});
Green
  • 507
  • 10
  • 20
1

Sharing what worked for me after googling for 2 hours, for firebase 9+

import { serverTimestamp } from "firebase/firestore";

export const postData = ({ name, points }: any) => {
  const scoresRef = collection(db, "scores");
  return addDoc(scoresRef, {
    name,
    points
    date: serverTimestamp(),
  });
};

Cristian Muscalu
  • 9,007
  • 12
  • 44
  • 76
0

I am using Firestore to store data that comes from a Raspberry PI with Python. The pipeline is like this:

Raspberry PI (Python using paho-mqtt) -> Google Cloud IoT -> Google Cloud Pub/Sub -> Firebase Functions -> Firestore.

Data in the device is a Python Dictionary. I convert that to JSON. The problem I had was that paho-mqtt will only send (publish) data as String and one of the fields of my data is timestamp. This timestamp is saved from the device because it accurately says when the measurement was taken regardless on when the data is ultimately stored in the database.

When I send my JSON structure, Firestore will store my field 'timestamp' as String. This is not convenient. So here is the solution.

I do a conversion in the Cloud Function that is triggered by the Pub/Sub to write into Firestore using Moment library to convert.

Note: I am getting the timestamp in python with:

currenttime = datetime.datetime.utcnow()

var moment = require('moment'); // require Moment 
function toTimestamp(strDate){
  return parsedTime = moment(strDate, "YYYY-MM-DD HH:mm:ss:SS");
 }

exports.myFunctionPubSub = functions.pubsub.topic('my-topic-name').onPublish((message, context) => {

  let parsedMessage = null;
  try {
    parsedMessage = message.json;

    // Convert timestamp string to timestamp object
    parsedMessage.date = toTimestamp(parsedMessage.date);

    // Get the Device ID from the message. Useful when you have multiple IoT devices
    deviceID = parsedMessage._deviceID;

    let addDoc = db.collection('MyDevices')
                    .doc(deviceID)
                    .collection('DeviceData')
                    .add(parsedMessage)
                    .then ( (ref) => {
                      console.log('Added document ID: ', ref.id);
                      return null;
                    }).catch ( (error) => {
                      console.error('Failed to write database', error);
                      return null;
                    });

  } catch (e) {
    console.error('PubSub message was not JSON', e);
  } 

  // // Expected return or a warning will be triggered in the Firebase Function logs.
  return null;  
});
Cesar
  • 81
  • 2
0

Firestone method does not work. Use Timestamp from java.sql.Timestamp and don't cast to string.. Then firestone formats it properly. For example to mark a now() use:

val timestamp = Timestamp(System.currentTimeMillis())
0

multiple ways to store time in Firestore

  1. firebaseAdmin.firestore.FieldValue.serverTimestamp() method. The actual timestamp will be computed when the doc is written to the Firestore.
    while storing it looks like this:

enter image description here

  1. firebaseAdmin.firestore.Timestamp.now() method.
    while storing it looks like this:

enter image description here

For both the methods, next time you fetch data it will return Firestore Timestamp object:

enter image description here

So, you first need to convert it to native js Date object and then you can perform methods on it like toISOString().

export function FStimestampToDate(
  timestamp:
    | FirebaseFirestore.Timestamp
    | FirebaseFirestore.FieldValue
): Date {
  return (timestamp as FirebaseFirestore.Timestamp).toDate();
}
  1. Store as unix timestamp Date.now, it'll be stored as number i.e. 1627235565028 but you won't be able to see it as readable Date in firestore db.
    To query on this Firestore field, you need to convert the date to timestamp and then query.

  2. Store as new Date().toISOString() i.e. "2021-07-25T17:56:40.373Z" but you won't be able to perform date range query on this.

I prefer the 2nd or 3rd way.

GorvGoyl
  • 42,508
  • 29
  • 229
  • 225
  • Assuming all dates use the same timezone, the strings generated by #4 are actually sortable. I.e. for ISOString, alphanumeric sort works exactly as date sort. This means that you can do range query using on these strings. – danbars Feb 04 '22 at 04:09
0

In the version 9 just use the following import.

import { Timestamp } from '@angular/fire/firestore'

Your code will look like this:

ref.child(key).set({
  id: itemId,
  content: itemContent,
  user: uid,
  createdAt: Timestamp.fromDate(new Date())
})
LuscaDev
  • 329
  • 3
  • 8
0

in flutter:

final docData = {
  "stringExample": "Hello world!",
  "booleanExample": true,
  "numberExample": 3.14159265,
  "dateExample": Timestamp.now(),  <------
  "listExample": [1, 2, 3],
  "nullExample": null
};
-1

Swift 5.1

...
"dateExample": Timestamp(date: Date()),
...
Stephane Paquet
  • 2,315
  • 27
  • 31
  • 3
    the most important point of using a Timestamp is to generate it on the server. By initializing it with Date(), you generate a client timestamp which, if your computer's date is set wrong, won't generate a correct date. If your app is relying on timestamps to order data, this won't work. Use the accepted answer instead – Dany Dhondt Apr 24 '20 at 10:59
-1

The newest version from Firestore you should use it as follow

import { doc, setDoc, Timestamp } from "firebase/firestore"; 

const docData = {
    ...
    dateExample: Timestamp.fromDate(new Date("December 10, 1815"))
};
await setDoc(doc(db, "data", "one"), docData);

or for sever timestamp

import { updateDoc, serverTimestamp } from "firebase/firestore";

const docRef = doc(db, 'objects', 'some-id');

const updateTimestamp = await updateDoc(docRef, {
   timestamp: serverTimestamp()
});
Moumen Lahmidi
  • 462
  • 5
  • 7