After experimenting with different methods (outlined below), I found a solution that worked for me:
1. Transfer data using a custom function utilizing the @angular/fire SDK:
// firebase.service.ts
import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';
import { first, map } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class FirebaseService {
fromCollection = '<name-of-collection>';
toCollection = '<other-root-level-collection>/<document-id>/<subcollection>';
constructor(private firestore: AngularFirestore) {}
migrateTransactions() {
this.getAllDocuments<YourType>(this.fromCollection).subscribe((documents) => {
documents.forEach(async (document) => {
await this.createDocument(this.toCollection, document);
});
});
}
getAllDocuments<T>(path: string) {
return this.firestore
.collection(path)
.get()
.pipe(
first(),
map((collection) => collection.docs.map((doc) => doc.data() as T))
);
}
createDocument(path: string, document: unknown) {
return this.firestore.collection(path).add(document);
}
}
Note: This method only ADDS all documents from the original collection to the specified collection - it does NOT delete the original documents or overwrite existing ones, ensuring safety.
You can subsequently remove the original collection in the Firebase console.
Keep in mind you can concatenate nested collections and documents when passing them as arguments to
AngularFirestore.collection(path)
(as demonstrated in the property
toCollection
). This simplifies navigation through nested collections. Other SDKs may not support this feature.
2. Utilize firestore-migrator by Jeff Delaney:
This approach did not work for me due to issues with converting firebase's timestamps. However, if your schema does not contain complex data types, it might be suitable. The library itself is useful and can be adjusted locally with some tinkering.
3. Use the Cloud Firestore managed export and import service:
This is ideal for complete backups of either the entire database or a root level collection. It may not meet every requirement, so evaluate if it aligns with your needs.