0

When a push event happens it will return back a new key.

For example from the Docs:

// Generate a reference to a new location and add some data using push()
var newPostRef = postsRef.push();

// Get the unique ID generated by push()
var postID = newPostRef.key();

What I'm trying to do:

Now I want to use this key directly after in order to effect change in another part of the database.

But because of the asynchronous nature of JavaScript I've been getting tripped up.

I've tried the success callback:

var newMessageIDRef =  firebaseMessagesRef.push({
  authorName: 'Nick',
  text:"Hello!"
},printKey(newMessageIDRef));

var printKey = function(newMessageIDRef) {
  console.log(newMessageIDRef);//undefined
}

(I assume that printKey is being called before newMessageIDRef is set)

I've tried using "then":

var newMessageIDRef =  firebaseConvosRef.push({
    authorName: 'Nick',
    text:"Hello!",
}).then(printKey(newMessageIDRef));

var printKey = function(newMessageIDRef) {
  console.log(newMessageIDRef);//undefined
}

(I assume the parens is causing printKey to be immediately executed, which makes me wonder how I add params but not cause early execution)

Question:

Is there some conventional way to handle something so common or is my best solution to use a Promise and handle the key with resolve?

Update(not answered yet though):

Below is working but it doesn't make sense.

var printKey = function(newMessageIDRef) {
    console.log(newMessageIDRef);//undefined
}

var newMessageIDRef =  firebaseConvosRef.push({
    authorName: 'Nick',
    text:"Hello!",
});
printKey(newMessageIDRef)

I would think that newMessageIDRefwould not necessarily be returned by the time printKey was called.

Nick Pineda
  • 6,354
  • 11
  • 46
  • 66

3 Answers3

1

According to the documentation, .push() works as follows :

  • returns "a Firebase reference for the generated location"
  • accepts, as second arg, a callback function that "will be called when the specified value is synchronized to the Firebase servers". The callback accepts one parameter, an error object if an error occurred, otherwise null.

Hence, in order to use the returned reference in the callback, it must be assigned, then accessed by the callback as an outer var.

var newMessageIDRef = firebaseMessagesRef.push({
    authorName: 'Nick',
    text:"Hello!"
}, printKey);

var printKey = function(err) {
    if(!err) {
        console.log(newMessageIDRef);
    }
}

Alternatively, you can promisify with one of (at least) two Firebase promisifiers, both of which seem fine but currently lack concrete examples of their promisified .push() in the documentation :

Fireproof

This is an educated guess as to how it might work :

var fireproofMessagesRef = new Fireproof(firebaseMessagesRef);

fireproofMessagesRef.push({
    authorName: 'Nick',
    text:"Hello!"
}).then(successHandler, errorHandler);

function successHandler(childIDRef) {
    console.log(childIDRef);
}
function errorHandler(err) {
    console.error(err);
}

Firebase-promisified

Again, an educated guess :

// having promisified Firebase.
firebaseMessagesRef.promisePush({
    authorName: 'Nick',
    text:"Hello!"
}).then(successHandler, errorHandler);

function successHandler(childIDRef) {
    console.log(childIDRef);
}
function errorHandler(err) {
    console.error(err);
}

My main uncertainty in both cases is whether childIdRef appears as a param in the success handler, which would seem sensible but I can't find confirmation.

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
1

The Firebase JavaScript SDK does not expose any promises, so there is no then(). It instead works based on callbacks.

Aside from that, I am not completely sure what you are trying to accomplish. So I'll just give some common snippets in hopes that one of them helps.

Firebase's push() operation is a pure client-side operation. It does not perform a round-trip to the server, but generates a statistically unique ID on the client.

Now let's assume that you want to create a new post (under /posts/$postid) and add a link to that new post to another location of the database (say /users/$uid/posts/$postid):

// Generate a reference to a new location and add some data using push()
var newPostRef = postsRef.push();

// Get the unique ID generated by push()
var postID = newPostRef.key();

// ref is a reference to the root, uid is the id of the current user
var userRef = ref.child('users').child(uid);

// Write the post to Firebase
newPostRef.set({ title: 'Firebase: Using the newly created key...', uid: uid }, function(newRef) {
    userRef.child('posts').child(postID).set(true);
});

You'll note that I don't use the newRef inside the callback. Since I already know what postID is.

The above approach will perform two write operations to Firebase:

  1. the actual post
  2. the link to the post in the user's profile

Since Firebase 2.4 (for JavaScript, 2.3 for Android and iOS) it is possible to perform both writes as a single operation. This again makes use of the fact that we can "pre-calculate" the post-ID as a client-side push() operation:

var ref = new Firebase('https://your-app.firebaseio.com');
var postsRef = ref.child('posts');

// Get a unique ID generated by push()
var postID = postsRef.push().key();

// Create a single object, where we'll put all updates
var updates = {};

// We'll put the post into /posts/$postId
updates['/posts/'+postID] = { title: 'Firebase: Using the newly created key...', uid: uid };

// Put the postId under /users/$uid/posts/$postId
updates['/users/'+uid+'/posts/'+postID] = true;

// Now write to both locations in one "big" swoop:    
ref.update(updates);

Read more about this in:

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • The fact that push "is a pure client-side operation. It does not perform a round-trip " like @FrankvanPuffelen says makes a lot more sense out of the issue. Getting undefined in the success callback or using "then" lead me to believe there was an asynchronous issue causing the problem. – Nick Pineda Nov 06 '15 at 20:39
  • The only issue now is how do we roll back the second write operation in the case that the first write operation failed? – Nick Pineda Nov 06 '15 at 20:42
  • Or does the fan-out strategy cover the case of failure in one of the writes? – Nick Pineda Nov 06 '15 at 21:14
  • The second solution I provide sends a single command to the Firebase server. So no need for rollback. – Frank van Puffelen Nov 06 '15 at 21:38
0

Both push and then expect a callback function as their argument. You will have to pass printKey itself, instead of calling it (with what?!) and passing its result. It should be

function printKey(newMessageIDRef) {
  console.log(newMessageIDRef);
}
firebaseConvosRef.push({
    authorName: 'Nick',
    text:"Hello!",
}).then(printKey);
//      ^^^^^^^^
Bergi
  • 630,263
  • 148
  • 957
  • 1,375