Aritra Dattagupta
Aritra Dattagupta

Reputation: 830

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?

Upvotes: 5

Views: 2639

Answers (3)

ganiular
ganiular

Reputation: 629

From the structure of your data, the field board.columns is a list of object that includes Timestamp data type. Firebase have not yet support inserting Timestamp in a list of objects. To avoid this error you can remove the Timestamp fields.

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

for (var object in (json['columns'])) {
    object as Map
        ..remove('createdAt')
        ..remove('updatedAt');
}

await doc.set(json);

But somehow if the you really need the Timestamp data, you can consider converting the fields to string or int

Upvotes: -1

webstar
webstar

Reputation: 114

In Javascript, You can also use new Date(), which automatically converts into firebase timestamp in the firestore database.

Upvotes: 1

Renaud Tarnec
Renaud Tarnec

Reputation: 83048

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.

Upvotes: 8

Related Questions