0

I have a very simple flow which fetch (list) all staff, then loop them and upon looping each user, insert into another firebase doc

  async insertAchivementTest() {
    let eeRef = this.afStore.collection<any>(`.../EmpSnapshot`).ref
    let eeDoc: any = eeRef
    eeDoc = eeDoc.where("employment.event", "not-in", ["TER", "RSG"])  // only active staff

    await eeDoc.get().then(async res => {
      for (let ee of res.docs) {            // loop active EE
        console.log(`proc ee = ${ee.id}`)

        // each emp, loop find evaluators
        let eeEvaluators = [] // array of object

        let formEvaluators = [{ type: 'BY_ROLE', role: '_DIRECT_REPORT_' }]
        formEvaluators.forEach(async ev => {
          await this.afStore.doc<any>(`...udion.com`).ref.get().then(res => {
            eeEvaluators.push(res.data())
          })
        })
        let achievementData = {
          email: ee.id,
        //   evaluators: ['A', 'B'],
          evaluators: eeEvaluators,
        }
        console.log('show achievement before insert...=', achievementData)
        await this.afStore.collection(`.../Collection/Achievements`)
          .ref
          .add(achievementData)
      }
    })
  }

To ensure the correct data are fetched and insert into new doc, i have console.log them BEFORE insert as firebase doc (check the console log screenshot below) enter image description here ARRAY variable eeEvaluators is an array of object, it contain a field 'evaluators' with value shown in console log. But how come every time it tries to store into firebase doc via .add(...), the field 'evaluators' is always an empty array?

note: i am using angularfire package

// Firebase package
import {
    AngularFirestore,
    AngularFirestoreCollection
} from "@angular/fire/firestore";
import { AngularFireStorage } from "@angular/fire/storage";

updates 20 May 8AM: I spotted the weird behaviour, if i move out the retrieval logic from loop, it does insert into doc correctly. Can't find any weirdo in the loop logic. Somemore, the loop is jz LOOP-ONCE as u see the logic. I am PRETTY-MUCH confirmed the weird behavior caused by the loop, but i have to have a loop to support my business logic.

        // let formEvaluators = [{ type: 'BY_ROLE', role: '_DIRECT_REPORT_' }]
        // formEvaluators.forEach(async ev => {
        //     await this.afStore.doc<any>(`...udion.com`).ref.get().then(resUser => {
        //         eeEvaluators.push(resUser.data())
        //     })
        // })

        // CHANGE TO following code (no loop)
        await this.afStore.doc<any>(`...udion.com`).ref.get().then(resUser => {
                eeEvaluators.push(resUser.data())
            })

enter image description here

update 20 May 1140AM: I found the explanation here, forEach doesn't work well for async/await, https://stackoverflow.com/a/37576787/8163746 so i replaced

formEvaluators.forEach(async ev => {

with

for (const ev of formEvaluators) 

in my code and it jz work!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Weilies
  • 500
  • 1
  • 7
  • 27

2 Answers2

0

Thats because you have too many nested data. Firebase does not support arrays directly in the way how you want to use it. You can store it as a map there however i would suggest you to create a new subcollection and then store those values. In the case if you have structures likes this and if you want apply them to firebase you have to use subcollections or normal collections on the root. Firebase is not designed to depict data like how you prepared your data. Create a subcollection with "evaluators" and keep the data which is saved there as flat as possible. One other thing of your data structures are that you cannot update them. If you want to update a single field within "evaluators" you cannot do it. You have to update the complete tree structure of the field "evaluators". However if you use collections / subcollections you can manage updates, inserts and deletes far better than nested maps saved in a single field.

esen
  • 90
  • 5
  • i may not agree with your comment. I sometime perform very simple insert for very complex structure without any issue. For this round, it does insert but only the ARRAY from doc doesn't insert (the rest of the field in same doc are ok). Also, there ain't any 'catch' return. I updated my works above, moving out from the loop does work. Not sure why... But the nature of my logic, i must perform a loop for additional fetch – Weilies May 20 '21 at 00:36
0

I found the explanation here, forEach doesn't work well for async/await, https://stackoverflow.com/a/37576787/8163746 so I replaced

formEvaluators.forEach(async ev => {

with

for (const ev of formEvaluators) 

in my code and it just works!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Weilies
  • 500
  • 1
  • 7
  • 27