angularfirebasegoogle-cloud-firestore

It is possible to copy firebase document and all it sub collection to another document using angular


enter image description here

Hello all, As we see an example from the picture I would like to copy all the documents (and its data) containing in collection('planaprendizaje').

For example take the data from document 1 and put on document 10. Choosing if I want planaprendizaje or another sub collection.

I am using angular to connect to firebase in order to try get the data.


Solution

  • this is my solution but using callable cloud functions. You can play with source and dest params.

    const functions = require( 'firebase-functions' );
    const admin = require( 'firebase-admin' );
    
    const copyDoc = async ( source, dest ) => {
      const docRef = admin.firestore().doc( source );
    
      const docData = await docRef
        .get()
        .then( ( doc ) => doc.exists && doc.data() )
        .catch( ( error ) => {
          console.error( 'Error reading document', `${source}`, error.message );
          throw new functions.https.HttpsError( 'not-found', 'Copying document was not read' );
        } );
    
      if ( docData ) {
        await admin
          .firestore()
          .doc( dest )
          .set( docData )
          .catch( ( error ) => {
            console.error( 'Error creating document', `${dest}`, error.message );
            throw new functions.https.HttpsError(
              'data-loss',
              'Data was not copied properly to the target collection, please try again.',
            );
          } );
      }
    
      const subcollections = await docRef.listCollections();
      for await ( const subcollectionRef of subcollections ) {
        const subPath = `${source}/${subcollectionRef.id}`
        console.log( 'parsing: ', subPath )
        try {
          const snapshot = await subcollectionRef.get()
          const docs = snapshot.docs;
          for await ( const doc of docs ) {
            console.log( `coping: ${subPath}/${doc.id} -> ${dest}/${subcollectionRef.id}/${doc.id}` )
            await copyDoc( `${subPath}/${doc.id}`, `${dest}/${subcollectionRef.id}/${doc.id}` );
          }
        } catch ( e ) {
          throw new functions.https.HttpsError(
            'data-loss',
            `${e.message} -> ${subPath}, please try again.`,
          )
        }
      }
    }
    
    exports.set = functions
      .region( 'europe-west3' )
      .https.onCall( async ( {source_doc, destination_doc}, context ) => {
        if ( !context.auth ) {
          // Throwing an HttpsError so that the client gets the error details.
          throw new functions.https.HttpsError( 'unauthenticated', 'The function must be called while authenticated.' );
        }
        try {
          await copyDoc( source_doc, destination_doc )
          return { result: destination_doc  }
        } catch ( e ) {
          throw new functions.https.HttpsError( 'aborted', e.message );
        }
      } );