0

I'm working with Firebase and Javascript. I need to get the key to a reference that was created by push().

My code waits on the promise returned by push and then reads the key. It looks like this:

firebase.database().ref("preds/").push()
.then(function(newReference){
    console.log(newReference.key);
});

Now I'm looking at a section of code written by a colleague. It doesn't use promises. Instead, it makes direct use of the key:

var newReference = firebase.database().ref("preds/").push()
console.log(newReference.key)

This does look much nicer (especially since the real code is longer than these examples). But I suspect that it might be a race condition. What if we're still waiting for a response from the database and the key is already used ? But I was not able to produce problems with his code.

I looked at the Firebase docs, and they are a bit confusing. It says that push() returns a:

Combined Promise and Reference; resolves when write is complete, but can be used immediately as the Reference to the child location.

Their example looks like this:

var messageListRef = firebase.database().ref('message_list');
var newMessageRef = messageListRef.push();
newMessageRef.set({
  'user_id': 'ada',
  'text': 'The Analytical Engine weaves algebraical patterns just as the Jacquard loom weaves flowers and leaves.'
});

This looks similar to the use of newReference.key, but none of it is blocking. If I understand correctly, these functions are just chained up for asynchronous execution. However, they do say that the reference can be used immediately to access the child location.

I searched SO and found this question: In Firebase when using push() How do I pull the unique ID Dan_Mindru says:

To anybody finding this question & using Firebase 3+, the way you get auto generated object unique ids after push is by using the key property (not method) on the promise snapshot

And his code looks just like my initial version:

firebase
  .ref('item')
  .push({...})
  .then((snap) => {
     const key = snap.key 
  })

I know this is a very common question around firebase, but I hope I have supplied enough context to justify my confusion. What is the proper way to get the key of a newly created reference ? Do I have to wait for the promise or can I directly access the key ?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
lhk
  • 27,458
  • 30
  • 122
  • 201

1 Answers1

1

The key that is generated when you call push() is a pure client-side operation. No call to the server is involved when you call push() without arguments. So the first two snippets of code you shared are equivalent.

In your last code snippet the push({...}) does call out to the server to write the object to the database. But here too the key for the new child node is generated in the client-side code.

For more on these push IDs, see the blog post: The 2^120 Ways to Ensure Unique Identifiers.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • That's great, thanks. (I thought the key might require communication with the server. Not necessarily to avoid clashes, I know they are very unlikely. But to ensure a proper ordering. The keys are created from a timestamp and ordered by time. So without some sync this invariant of order in time might be broken. But maybe they don't make hard assumptions about it) – lhk Sep 25 '18 at 14:08
  • When the client establishes its initial connection, it determines its offset to the server's time. This is used on calculating the push IDs. The offset is also exposed on `.info/serverTimeOffset`: https://firebase.google.com/docs/database/web/offline-capabilities#clock-skew. – Frank van Puffelen Sep 25 '18 at 14:15