dontknowhy
dontknowhy

Reputation: 2866

Cloud Functions, Firestore trigger, recursive delete not working

Currently, I`m trying to delete all the nested hirachy datas when some documents deleted using Firestore Trigger

and my code and error code are below

const admin = require('firebase-admin');
const firebase_tools = require('firebase-tools');
const functions = require('firebase-functions');

admin.initializeApp({   
}
);


exports.firestore_delete_trigger_test = functions.firestore
  .document('collection1/{docs1}/collection2/{docs2}')
  .onDelete(async (change: any, context: any) => {     
    
    const path = change.path;

    await firebase_tools.firestore
      .delete(path, {
        project: process.env.GCLOUD_PROJECT,
        recursive: true,
        yes: true,
        token: functions.config().fb.token
      });

    return {
      path: path
    };

  });

and the Error code is below

FirebaseError: Must specify a path.
    at Object.reject (/workspace/node_modules/firebase-tools/lib/utils.js:122:27) 

why it shows error code? I do not want "callable functions" because of security

Upvotes: 1

Views: 633

Answers (1)

samthecodingman
samthecodingman

Reputation: 26171

Don't ever use any when writing in TypeScript as you essentially "switch off" TypeScript and lose valuable type information such as why your code isn't working.

If you use the following lines, the type of change (which should be snapshot) and context are automatically set as QueryDocumentSnapshot and EventContext respectively as defined by the onDelete method.

exports.firestore_delete_trigger_test = functions.firestore
  .document('collection1/{docs1}/collection2/{docs2}')
  .onDelete(async (snapshot, context) => {

  });

Note: A QueryDocumentSnapshot is like a regular DocumentSnapshot, but it is guaranteed to exist (snap.exists always returns true and snap.data() will never return undefined).

Now that the type is restored to snapshot, you'll see that you can't read a property called path from it as it's not set. In your current code, path will just be set to undefined, which leads to the error saying you need to specify a path.

const path = snapshot.path; // ✖ Property 'path' does not exist on type 'QueryDocumentSnapshot'. ts(2339)

This is because path is a property of DocumentReference. To get the snapshot's underlying DocumentReference, you access it's ref property.

const path = snapshot.ref.path; // ✔

Next, in Node 10+ Cloud Functions, the list of available environment variables was changed and process.env.GCLOUD_PROJECT was removed. To get the current project ID, you can use either

const PROJECT_ID = JSON.parse(process.env.FIREBASE_CONFIG).projectId;

or

const defaultApp = admin.intializeApp();

const PROJECT_ID = defaultApp.options.projectId;

This then makes your (modernized) code:

import * as admin from 'firebase-admin';
import * as firebase_tools from 'firebase-tools';
import * as functions from 'firebase-functions';

const PROJECT_ID = JSON.parse(process.env.FIREBASE_CONFIG).projectId;

admin.initializeApp(); // config is automatically filled if left empty
                       // although it isn't needed here

export const firestore_delete_trigger_test = functions.firestore
  .document('collection1/{docs1}/collection2/{docs2}')
  .onDelete(async (snapshot, context) => {     
    const path = snapshot.ref.path;

    await firebase_tools.firestore
      .delete(path, {
        project: PROJECT_ID,
        recursive: true,
        yes: true,
        token: functions.config().fb.token
      });

    return {
      path: path
    };
  });

Upvotes: 1

Related Questions