How to delete a deeply nested field inside a Firebase Object map

Viewed 413

I have a firebase Object map called "CourseList" which contains nested fields. These nested fields themselves are Object maps which contain further nested fields. Also, some of these object maps will have randomly generated names.

The goal is to delete the Object map with the randomly generated name of "352oIP3fdc6IIvuBbajR0" (underlined in BLUE). The names of "CourseList" and "LectureList" are static names, however the red CourseID (with a randomly generated name of "2dfPipFRKiB6TAKab4jv8").

enter image description here

By following other questions on stackOverflow, I was able to get the delete functionality working if I wanted to delete the Red object map "2dfPipFRKiB6TAKab4jv8".

let CID = '2dfPipFRKiB6TAKab4jv8';

await db.collection('users').doc(UID).set( { 
  CourseList : { [CID]: FieldValue.delete() }
    
},{ merge: true }
);

However, when I try to delete the sub-object map underlined in blue of "352oIP3fdc6IIvuBbajR0", the operation appeared to not do anything, and the Firebase document was unchanged.

let CID = "2dfPipFRKiB6TAKab4jv8";
let LID = "352oIP3fdc6IIvuBbajR0";

await db.collection('users').doc(UID).set( { 
  CourseList : { [`${CID}.LectureList.${LID}`]: FieldValue.delete() }

},{ merge: true }
    );

Any clarity as to how to properly delete a deeply nested field inside an object map would be greatly appreciated.

3 Answers

SOLUTION:

For future readers, this is the code I used to delete highly nested fields inside an Object Map.

      const userRec = db.collection('users').doc(UID);
      let userRecData = await userRec.get();
      let userRecResp = {};
      userRecResp = userRecData.data();
      delete userRecResp.CourseList[CID]['LectureList'][LID];  
      await db.collection('users').doc(UID).update(userRecResp); 

Please note, "UID", "CID", and "LID" are variable names.

You need to specify the full path of the nested value as the key of the object passed to set(). You can't express it as a series of nested objects as you are now.

await db.collection('users').doc(UID).set({ 
  [`CourseList.${CID}`]: FieldValue.delete()
},
{ merge: true }
);

Althrough the post is old, In case anybody finds this later

for DOT paths to work you have to use update instead of set, set does not handle DOT paths, even merge. Merge will merge all the supplied nested object so data is not smashed.

SOLUTION:

For the delete to work you need to call

let CID = "2dfPipFRKiB6TAKab4jv8";
let LID = "352oIP3fdc6IIvuBbajR0";

await db.collection('users').doc(UID).update( {
 [`CourseList.${CID}.LectureList.${LID}`]: FieldValue.delete() 
} )

HOW TO DO THE SAME WITH SET+MERGE:

for the same to work with set + merge:true it has to be

let CID = "2dfPipFRKiB6TAKab4jv8";
let LID = "352oIP3fdc6IIvuBbajR0";

await db.collection('users').doc(UID).set({ 
  'CourseList': { 
    [CID]: {
      'LectureList': {
        [LID]: {
          FieldValue.delete() 
        }
      }
    }
  },
  { merge: true }
);

No reason to do the set, route here, as update is cleare, but it helps to clarify the difference with he operations

WHY ONE OF THE DELETE WORKED:

@andrewB your deletion by CID worked because there is not nested path

The below code worked becasue it did the following:

let CID = '2dfPipFRKiB6TAKab4jv8';

await db.collection('users').doc(UID).set( { 
  CourseList : { [CID]: FieldValue.delete() }
},{ merge: true }
);
  1. attempt to replace key CourseList in users/${UID with { [CID]: FieldValue.delete() }
  2. because of merge: true, the replace is combined with the existing value there and ends up only touching the key [CID] instead of smashing the entire object
Related