firebasegoogle-cloud-platformgoogle-cloud-firestore

Firebase Firestore timestamp not allowed inside array


I have a firestore data model like below

board :{
  id: string,
  name: string,
  cratedAt: Timestamp,
  updatedAt: Timestamp,
  owner: string,
  columns: [{
    name: string,
    createdAt: Timestamp,
    updatedAt: Timestamp,
  }]

The problem is I can't add timestamp inside arrays as it isn't supported by firebase. So my options are to go for separate root collection and store the id's inside the "columns" array or go for subcollections. But won't this increase the number of reads and consequently the price/bill of my overall transaction? How do I avoid this?


Solution

  • Indeed it is not possible to add a timestamp with firebase.firestore.FieldValue.serverTimestamp() inside an array. See here for more details on the reason why it is not possible. The usual workaround is to change the Array to a Map.

    But there is another possible workaround with a Cloud Function:

    Since you have, in your doc, two fields which hold a timestamp (createdAt and updatedAt), you can assign the value of those fields (generated via FieldValue.serverTimestamp()) to the array elements, with a Cloud Function called when the doc is created.

    The following Cloud Function code shows how to do for one element in the columns array. It's up to you to adapt it to cover arrays with more than one element.

    exports.updateTimeStampsInArray = functions.firestore
        .document('myCollection/{docId}')
        .onCreate((snap, context) => {
    
            const newValue = snap.data();
            const createdAt = newValue.createdAt;
    
            const columnsArray = newValue.columns;
    
            const newColumnsArray = [];
            newColumnsArray.push({ name: columnsArray[0].name, createdAt: createdAt });
    
            return snap.ref.update({ columns: newColumnsArray })
        });
    

    You need to create the doc as follows:

      db.collection('myCollection')
        .doc('...')
        .set({
          createdAt: firebase.firestore.FieldValue.serverTimestamp(),
          columns: [{ name: 'TheName' }],  
        });
    

    As soon as the CF will run, it will populate the Array element with the value of the createdAt Timestamp.