How to make a firebase cloud onUpdate function to work properly? - javascript

I have adding and outputing comments in appliction.
That should work in realy time.
In my Comments component where which is statful component I have entire logic for geting data and saving in the firebase.
Now I want here to add a onUpdate fb cloud function.
I tried on next way and does not work:
const onCommentsAdded = this.runtime.fb.ref('/comments').onUpdate((change) => {
const after = change.after;
console.log('This is after: ', after, change.after)
})
Application cannot be compiled, this is error:
Unhandled Rejection (TypeError): runtime.fb.ref(...).onUpdate is not a
function

Assuming you're looking at the Realtime Database on Firebase and not Firestore.
The library you are trying to access doesn't look correct. See the Database Events documentation.
const onCommentsAdded = functions.database.ref('/comments')
.onUpdate((change, _context) => {
const after = change.after;
console.log('This is after: ', after, change.after)
});
Try updating the function to use functions.database.ref instead of this.runtime.fb.ref

Related

I am having an issue when trying to retrieve data from Firestore using the Firebase JS SDK

I am having an issue when trying to retrieve data from Firestore using the Firebase JS SDK. I am receiving the following error:
TypeError: firebase_firestore__WEBPACK_IMPORTED_MODULE_3__.getDoc(...).data is not a function
I am trying to load the data using the following code:
useEffect(() => {
const getAuthorData = async () => {
setAuthorData(
await getDoc(doc(db, 'users', post.data.author)).data()
)
}
const p = getAuthorData()
console.log(p)
}, [])
I think have imported the necessary Firebase modules and initialized the app with the correct configuration. I have also checked that the getDoc function is returning a Firestore DocumentSnapshot object, but the data() method is not a function. Some data is showing behin the error
I would like to know if there is a problem with my code or if I am missing something else.
Any help would be appreciated, thanks!
The problem is that getDoc returns an object that does not have a method called data. It returns a promise. Your code right now is trying to call data() on that promise instead of first awaiting it. If you are trying to keep this at one line of code, you will have to force the await to happen first before the call to data() by using parenthesis:
(await getDoc(doc(db, 'users', post.data.author))).data()

How should I get API token before executing Unit Test cases?

Within my unit test cases, I'm trying to do unit tests against some data in the API therefore an API token is required. I'm hoping to find a way to call token API and store it in Redux before firing any API.
I'm aware of setup.js in Jest, tried calling my API there and store in Redux didn't work well. I don't think the setup.js waited the method to finish completely before starting the unit test.
// Within the Setup.js, I was calling method directly
const getAPItoken = async() => {
await getToken();
}
getAPItoken();
Currently I'm getting the API token in 1 of the Unit Test files. Upon the method completion, rest of the Unit Tests will run fine since they are getting the API token from Redux.
Sample of what I'm doing now
describe('Get API token', () => {
test('it should return true after getting token', async () => {
// Within the method itself, it actually store the token to redux upon receiving from API, also it will return TRUE upon success
const retrievedToken = await getToken();
expect(retrievedToken).toBeTruthy();
});
Is there a better way to handle this?
You can use globalSetup. It accepts an async function that is triggered once before all test suites.
So you can optain the API key and set it on node global object so you can access if from anywhere.
// setup.js
module.exports = async () => {
global.__API_KEY__ = 'yoru API key';
};
// jest.config.js
module.exports = {
globalSetup: './setup.js',
};

React Native Firebase transaction not working properly

I'm developing an App using React Native and Firebase Real-Time Database.
In the database, I have some data as below.
myRoot
|
|--myValue1: 0
|
|--myValue2: 2
Then, I want to increase those values by one and get the following result.
myRoot
|
|--myValue1: 1
|
|--myValue2: 3
For this, I used a function as follows.
myFunction = () => {
const myRef = firebase.database().ref('myRoot');
return myRef.transaction((data) => {
data.myValue1++;
data.myValue2++;
return data;
})
.then(console.log('Done'))
.catch((error) => console.log(error));
}
But, after calling the function, I get the following error.
[Unhandled promise rejection: TypeError: null is not an object (evaluating 'data.myValue1')]
I tried taking a snapshot of myRef and print it in the console. It worked and printed the current values. But, transaction does not work and gives null.
Please help me to solve this problem.
You'll need to check data for null, as this happens the first time the transaction handler function is called. The handler will get called again with the snapshot, if it's present at the location of the database where you are performing the transaction. You can see this check being performed in the sample code in the documentation.
Something like this I believe Sennen:
myFunction = () => {
const myRef = firebase.database().ref('myRoot');
myRef.transaction((data) => {
if(data) {
if(data.myValue1) {
data.myValue1++;
}
if(data.myValue2) {
data.myValue2++;
}
}
return data;
})
.then(console.log('Done'))
.catch((error) => console.log(error));
}
Found what caused the problem. The code segment is fine. The problem was in the dependencies. Just execute npm install firebase --save and then npm install. Restart the project. It worked!

React + Firestore : Return a variable from a query

I'm learning React and Firestore currently and am a bit stuck. I'm trying to retrieve a users name from a firestore collection by searching their uid.
The following code is executed in a map of 'lessons' to create a list.
{lesson.post_author && findName(lesson.post_author)}
The following code is the findName function.
let findName = uid => {
firebase.firestore().collection("users")
.where('uid', '==', uid)
.get()
.then(querySnapshot => {
console.log(querySnapshot.docs[0].data().name);
});
};
Currently, the findName function will console log all of the names to the console successfully. I've altered the code to be able to console log outside of the firestore call, but that returns a promise pending in console.
The goal of the code is to return the name rather then the uid in the list.
Any help would be much appreciated.
Thank you!
As others have explained, you can't return that value, since it's loaded from Firestore asynchronously. By the time your return runs, the data hasn't loaded yet.
In React you handle this by putting the data in the component's state, and using it from there. If you do this, your render method can simply pick it up from the state, with something like:
{lesson.post_author && findName(lesson.post_author_name)}
(the above assumes that lesson indirectly comes from the state.
It's a bit easier if we pretend there's only one lesson, and you have these values straight in the state:
{state.post_author && findName(state.post_author_name)}
Now I'll assume you already have the post_author and you just need to look up the author's name. That means that somewhere in/after componentDidMount you'll load the additional data and add it to the state:
componentDidMount() {
firebase.firestore().collection("users")
.where('uid', '==', this.state.uid)
.get()
.then(querySnapshot => {
this.setState({ post_user_name: querySnapshot.docs[0].data().name });
});
}
Now the loading of the data still happens asynchronously, so the call to setState() happens some time after componentDidMount has completed. But React is aware that changing the state may require a refresh of the component, so it responds to the call to setState() by rerendering it.
Note that I'd highly recommend using each user's UID as the ID of the documents in users. That way you don't need a query and can just do a directly lookup:
componentDidMount() {
firebase.firestore().collection("users")
.doc(this.state.uid)
.get()
.then(doc => {
this.setState({ post_user_name: doc.data().name });
});
}
I'm trying to retrieve a users name from a firestore collection by
searching their uid.
This is accomplished by using the asyncronous .get method on a Firestore reference. In your case, you probably have a users collection of firebase.auth().currentUser.uid named documents.
var userRef = firebase.firestore().collection('users').doc(users.uid);
userRef.get().then(function(doc) {
if (doc.exists) {
console.log("Users first name is:", doc.data().firstName);
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});

Firebase: Is the error handling in the firebase stripe function example enough?

Firebase provides samples on GitHub for writing cloud functions.
I have a question about the "createStripeCharge" function.
It is possible that the write to the database fails?
If this would be the case, this function charges a customer but no object would be saved to the database. Is this right?
This error handling cannot be enough or do I understand something wrong?
The following line in the code confuses me:
return event.data.adminRef.set(response);
You found the code on GitHub:
https://github.com/firebase/functions-samples/blob/master/stripe/functions/index.js
Or here:
exports.createStripeCharge = functions.database.ref('/stripe_customers/{userId}/charges/{id}').onWrite((event) => {
const val = event.data.val();
// This onWrite will trigger whenever anything is written to the path, so
// noop if the charge was deleted, errored out, or the Stripe API returned a result (id exists)
if (val === null || val.id || val.error) return null;
// Look up the Stripe customer id written in createStripeCustomer
return admin.database().ref(`/stripe_customers/${event.params.userId}/customer_id`).once('value').then((snapshot) => {
return snapshot.val();
}).then((customer) => {
// Create a charge using the pushId as the idempotency key, protecting against double charges
const amount = val.amount;
const idempotency_key = event.params.id;
let charge = {amount, currency, customer};
if (val.source !== null) charge.source = val.source;
return stripe.charges.create(charge, {idempotency_key});
}).then((response) => {
// If the result is successful, write it back to the database
return event.data.adminRef.set(response);
}).catch((error) => {
// We want to capture errors and render them in a user-friendly way, while
// still logging an exception with Stackdriver
return event.data.adminRef.child('error').set(userFacingMessage(error));
}).then(() => {
return reportError(error, {user: event.params.userId});
});
});
The only way a database write can fail is if it violates a security rule or if the function times out and gets cleaned up before it finishes. When using the admin SDK, security rules don't apply, so that can't be the cause. I suppose it's possible for the write to time out, so if you are very concerned about that, you should increase the timeout of the function. The chance of a timeout occurring is extremely low. If that happens, you should be able to manually resolve the concern of an end user without wasting a lot of time.
The onWrite():
triggers when data is created, updated, or deleted in the Realtime Database.
exports.createStripeCharge = functions.database.ref('/stripe_customers/{userId}/charges/{id}').onWrite((event) => {
Therefore if the write to the database in the above location fails then onWrite() will not trigger.
Also if you want it to trigger when adding data only then you can use onCreate():
It triggers when new data is created in the Realtime Database.
more info here:
https://firebase.google.com/docs/functions/database-events

Categories