2

I have Firebase Realtime Database data structured as below where I want to replace "-preliminaryId" with "-ultimateId123" in the "contacts" and "notes" nodes. To perform this I will delete the old nodes and replace them with new nodes.

"prel":{
  "-preliminaryId": {
    "email" : "hello@bye.com"
  }
},
"contacts": {
  "-ABC": {
     "-BCD": {
       "email": "bye@nowhere.com",
       "uid" : "-123456WWWXYz"
     },
     "-preliminaryId": {
       "email": "hello@bye.com",
       "uid": "-preliminaryId"
     }
  }
},
"notes": {
  "-noteIdone": {
    "access": {
      "members": {
        "-preliminaryId": 1
      }
    }
  },
  "-noteIdtwo": {
    "access": {
      "members": {
        "-realId1234": 1
      }
    }
  }
}

The new id for email "hello@bye.com" should be "-ultimateId123". (I cannot store email as keys in Firebase Realtime Database.)

I begin by fetching the preliminary id to replace.

  const prelSnap = await dbRoot.child('prel').orderByChild('email').equalTo('hello@bye.com').once('value')
  const prelData= prelSnap.val()
  console.log('prelData', prelData)
  const oldId = Object.keys(prelData)[0]

The prelData variable will be

{ -preliminaryId: { email: 'hello@bye.com' } } 

However, I would prefer it to just be

{ email: 'hello@bye.com' }

so I can get oldId by prelSnap.key instead of Object.keys(prelData)[0].

However, my real hurdle is fetching contacts

  const contactSnaps = await dbRoot.child('contacts').orderByChild(`${oldId}/uid`).equalTo(oldId).once('value')
  console.log('contactSnaps', contactSnaps.numChildren())
  contactSnaps.forEach((contact)=>{
    console.log('contactData', contact.val())
    const userId = Object.keys(contactData)[0] 
    ...
    // Replace the contact node
    myPromises.push(dbRoot.child(`contacts/${userId}/${newId}`).set(contactObj)) // Create new contact data
    myPromises.push(dbRoot.child(`contacts/${userId}/${oldId}`).remove()) // Delete old contact
    ...
  })

This will get me ALL contacts. The logout from console.log('contactData', contact.val()) will be:

numChildren 1

contactData {
   "-BCD": {
     "email": "bye@nowhere.com",
     "uid" : "-123456WWWXYz"
   },
   -preliminaryId: {
     "email": "hello@bye.com",
     "uid": "-preliminaryId"
   }
}

Hardcoded example:

const contactSnaps = await dbRoot.child('contacts').orderByChild('-preliminaryId/uid').equalTo('-preliminaryId').once('value')
console.log('contactSnapsHC', contactSnaps.numChildren())
contactSnaps.forEach((contact)=>{
  const contactData = contact.val()
  console.log('contactDataHC', contactData)
})

Output from above hardcoded example:

contactSnapsHC 1
contactDataHC { -BCD: { email: "bye@nowhere.com", uid : "-123456WWWXYz" }, -preliminaryId: { email: "hello@bye.com", uid: "-preliminaryId" } }

My guess is that this might be somewhat related to my issue with the first query?

When performing the same type of query on notes, all works well though.

nodeSnaps = await dbRoot.child('notes').orderByChild(`access/members/${oldId}`).equalTo(1).once('value')
console.log('notes', nodeSnaps.numChildren())
nodeSnaps.forEach((node)=>{
  console.log('notesData', node.val())
  ...
}

The output here will be:

notes 1
notesData { "access": { "members": { "-preliminaryId": 1 } } }

I expected the first two queries to return result at the same node level as the notes query.

How can I query the database to return the result shown below?

prelData { email: 'hello@bye.com' }
contactData { email: 'hello@bye.com', uid: '-preliminaryId' }

Kind regards /K

Kermit
  • 2,865
  • 3
  • 30
  • 53
  • firebase doesnt allow renaming a 'key' in the node ,what i would suggest it to do.you have remove the whole node and recreate it – m'hd semps Jul 21 '20 at 09:08
  • 1
    Is [this](https://stackoverflow.com/questions/39107274/is-it-possible-to-rename-a-key-in-the-firebase-realtime-database) a good refrence? – m'hd semps Jul 21 '20 at 09:10
  • Hi! Yes, my plan is to delete the old node and replace it with a new node! :D – Kermit Jul 21 '20 at 13:06
  • If I understand correctly, you're saying that this query `const contactSnaps = await dbRoot.child('contacts').orderByChild(`${oldId}/uid`).equalTo(oldId)` is not giving the expected results. If that is indeed the problem, can you reproduce the problem with hard-coded value for `oldId` and provide that in the code instead, so that. can try to reproduce it? – Frank van Puffelen Jul 21 '20 at 13:52
  • Hi @FrankvanPuffelen - Than you for the reply! I have added a hard coded example along with my printout. /K – Kermit Jul 21 '20 at 14:22

1 Answers1

1

I think your confusion is about what the query returns here:

dbRoot.child('contacts').orderByChild('-preliminaryId/uid').equalTo('-preliminaryId')

Firebase queries operate on a flat list. Since you query contacts, the nodes returned will be child nodes of contacts. Specifically, it returns any child node of contact for which a property -preliminaryId/uid exists, which has a value of -preliminaryId. In your example that is true for the node at contacts/-ABC, which is what the query returns for me.


For example, when I add another sibling node on the same level as ABC:

"contacts": {
  "-ABC": {
     "-BCD": {
       "email": "bye@nowhere.com",
       "uid" : "-123456WWWXYz"
     },
     "-preliminaryId": {
       "email": "hello@bye.com",
       "uid": "-preliminaryId"
     }
  },
  "DEF": {
     "-HKI": {
       "uid": "another id"
     }
  }
},

Your query in this case still only returns the -ABC node, since that's the only one where a -preliminaryId/uid exists with the correct value.

For a working example of this, see: https://jsbin.com/wivukeq/edit?js,console

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Ah, ok. That makes sense! :) I see now that the structure for 'notes' differs - there is one level less - that's what makes all the difference! :D /K – Kermit Jul 21 '20 at 15:12
  • I think I am beginning to understand what you mean when you say that "Firebase queries operate on a flat list" ;D Finally! Again - many thanks! /K – Kermit Jul 21 '20 at 15:37
  • Sure thing. You might also want to check out my answer here, as the type of dynamic query you do in general won't scale to long lists. https://stackoverflow.com/questions/40656589/firebase-query-if-child-of-child-contains-a-value – Frank van Puffelen Jul 21 '20 at 16:09