How to retrieve data from firebase and then update the data using Swift5 - firebase

After the current user watches the video ad, it will retrieve their point (which is stored in the firebase) and add 1 to their point. Then, it will update the document and also display the number of points the user has. It seems like everything is okay, except, I can't do scoreText.text = point
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd, didRewardUserWith reward: GADAdReward) {
let dBRef = Database.database().reference()
dBRef.child("Users").child(Auth.auth().currentUser!.uid).queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
guard let dict = snapshot.value as? [String:Any] else {
print("Error")
return
}
var point = dict["point"] as? Int
point!+=1
dBRef.child("users").child(Auth.auth().currentUser!.uid).setValue(["point": point])
scoreText.text = point
})
How would I display the user's points?
[UPDATED CODE]
Changed code to access Cloud Firestore, not Realtime Database
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd, didRewardUserWith reward: GADAdReward) {
//[START update_document-increment
let docRef = db.collection("users").document(UserID!)
// Atomically increment the population of the city by 1.
docRef.updateData([
"points": FieldValue.increment(Int64(1))
])
//[END update_document-increment]
//insert point value here
scoreText.text =

The code you're showing accesses the Realtime Database, while he screenshot shows Cloud Firestore. While both databases are part of Firebase, they're completely separate, and the API for one doesn't apply to the other.
To fix the problem, you will have to either use the Cloud Firestore API, or enter the data into the Realtime Database.

Related

How do I know if there are more documents left to get from a firestore collection?

I'm using flutter and firebase. I use pagination, max 5 documents per page. How do I know if there are more documents left to get from a firestore collection. I want to use this information to enable/disable a next page button presented to the user.
limit: 5 (5 documents each time)
orderBy: "date" (newest first)
startAfterDocument: latestDocument (just a variable that holds the latest document)
This is how I fetch the documents.
collection.limit(5).orderBy("date", descending: true).startAfterDocument(latestDocument).get()
I thought about checking if the number of docs received from firestore is equal to 5, then assume there are more docs to get. But this will not work if I there are a total of n * 5 docs in the collection.
I thought about getting the last document in the collection and store this and compare this to every doc in the batches I get, if there is a match then I know I've reach the end, but this means one excess read.
Or maybe I could keep on getting docs until I get an empty list and assume I've reached the end of the collection.
I still feel there are a much better solution to this.
Let me know if you need more info, this is my first question on this account.
There is no flag in the response to indicate there are more documents. The common solution is to request one more document than you need/display, and then use the presence of that last document as an indicator that there are more documents.
This is also what the database would have to do to include such a flag in its response, which is probably why this isn't an explicit option in the SDK.
You might also want to check the documentation on keeping a distributed count of the number of documents in a collection as that's another way to determine whether you need to enable the UI to load a next page.
here's a way to get a large data from firebase collection
let latestDoc = null; // this is to store the last doc from a query
//result
const dataArr = []; // this is to store the data getting from firestore
let loadMore = true; // this is to check if there's more data or no
const initialQuery = async () => {
const first = db
.collection("recipes-test")
.orderBy("title")
.startAfter(latestDoc || 0)
.limit(10);
const data = await first.get();
data.docs.forEach((doc) => {
// console.log("doc.data", doc.data());
dataArr.push(doc.data()); // pushing the data into the array
});
//! update latest doc
latestDoc = data.docs[data.docs.length - 1];
//! unattach event listeners if no more docs
if (data.empty) {
loadMore = false;
}
};
// running this through this function so we can actual await for the
//docs to get from firebase
const run = async () => {
// looping until we get all the docs
while (loadMore) {
console.log({ loadMore });
await initialQuery();
}
};

Firebase Function for Deleting Storage after 30 days

Frank van Puffelen has an example for deleting database after time.
https://stackoverflow.com/a/32012520/12253594
https://github.com/firebase/functions-samples/tree/master/delete-old-child-nodes
Which works wonders. But I'm wondering if it is possible for Storage as well?
Firebase Storage Structure
The structure: Experiences -> Experience_ID -> fullHD -> Image
And I want to delete including Experience_ID.
I'm thinking, something like:
exports.deleteOldItems = functions.storange.ref('/Experiences/{notification_id}')
.onWrite((change, context) => {
var ref = change.after.ref.parent; // reference to the items
var now = Date.now();
var cutoff = now - 2 * 60 * 60 * 1000;
var oldItemsQuery = ref.orderByChild('timestamp').endAt(cutoff);
return oldItemsQuery.once('value', function(snapshot) {
// create a map with all children that need to be removed
var updates = {};
snapshot.forEach(function(child) {
updates[child.key] = null
});
// execute all updates in one go and return the result to end the function
return ref.update(updates);
});
});
But I obviously don't have timestamps like I do in the database section.
So what do I do?
Best regards,
You have two main options.
Encode the date into the name of the file or its metadata, use the Cloud Storage list api to list all possible files, and check the file name or metadata to determine if it should be deleted. This solution doesn't scale very well as the number of possible files to be listed grows very large.
Mirror some data about each file in a database. For each file that you add to Cloud Storage, make an equivalent record in a database that includes both the timestamp and the path of the file. Since databases are easy to query, you can simply query the database to find the files that should be deleted.

minimize time operation in firebase/firestore

I build react native app with firebase & firestore.
what I'm looking to do is, when user open app, to insert/update his status to 'online' (kind of presence system), when user close app, his status 'offline'.
I did it with firebase.database.onDisconnect(), it works fine.
this is the function
async signupAnonymous() {
const user = await firebase.auth().signInAnonymouslyAndRetrieveData();
this.uid = firebase.auth().currentUser.uid
this.userStatusDatabaseRef = firebase.database().ref(`UserStatus/${this.uid}`);
this.userStatusFirestoreRef = firebase.firestore().doc(`UserStatus/${this.uid}`);
firebase.database().ref('.info/connected').on('value', async connected => {
if (connected.val() === false) {
// this.userStatusFirestoreRef.set({ state: 'offline', last_changed: firebase.firestore.FieldValue.serverTimestamp()},{merge:true});
return;
}
await firebase.database().ref(`UserStatus/${this.uid}`).onDisconnect().set({ state: 'offline', last_changed: firebase.firestore.FieldValue.serverTimestamp() },{merge:true});
this.userStatusDatabaseRef.set({ state: 'online', last_changed: firebase.firestore.FieldValue.serverTimestamp() },{merge:true});
// this.userStatusFirestoreRef.set({ state: 'online',last_changed: firebase.firestore.FieldValue.serverTimestamp() },{merge:true});
});
}
after that, I did trigger to insert data into firestore(because I want to work with firestore), this is the function(works fine, BUT it takes 3-4 sec)
module.exports.onUserStatusChanged = functions.database
.ref('/UserStatus/{uid}').onUpdate((change,context) => {
const eventStatus = change.after.val();
const userStatusFirestoreRef = firestore.doc(`UserStatus/${context.params.uid}`);
return change.after.ref.once("value").then((statusSnapshot) => {
return statusSnapshot.val();
}).then((status) => {
console.log(status, eventStatus);
if (status.last_changed > eventStatus.last_changed) return status;
eventStatus.last_changed = new Date(eventStatus.last_changed);
//return userStatusFirestoreRef.set(eventStatus);
return userStatusFirestoreRef.set(eventStatus,{merge:true});
});
});
then after that, I want to calculate the online users in app, so I did trigger when write new data to node of firestore so it calculate the size of online users by query.(it works fine but takes 4-7 sec)
module.exports.countOnlineUsers = functions.firestore.document('/UserStatus/{uid}').onWrite((change,context) => {
console.log('userStatus')
const userOnlineCounterRef = firestore.doc('Counters/onlineUsersCounter');
const docRef = firestore.collection('UserStatus').where('state','==','online').get().then(e=>{
let count = e.size;
console.log('count',count)
return userOnlineCounterRef.update({count})
})
return Promise.resolve({success:'added'})
})
then into my react native app
I get the count of online users
this.unsubscribe = firebase.firestore().doc(`Counters/onlineUsersCounter`).onSnapshot(doc=>{
console.log('count',doc.data().count)
})
All the operations takes about 12 sec. it's too much for me, it's online app
my firebase structure
what I'm doing wrong? maybe there is unnecessary function or something?
My final goals:
minimize time operation.
get online users count (with listener-each
change, it will update in app)
update user status.
if there are other way to do that, I would love to know.
Cloud Functions go into a 'cold start' mode, where they take some time to boot up. This is the only reason I can think of that it would take that long. Stack Overflow: Firebase Cloud Functions Is Very Slow
But your cloud function only needs to write to Firestore on log out to
catch the case where your user closes the app. You can write to it directly on log in from your client
with auth().onAuthStateChange().
You could also just always read who is logged in or out directly from the
realtime database and use Firestore for the rest of your data.
You can rearrange your data so that instead of a 'UserStatus' collection you have an 'OnlineUsers' collection containing only online users, kept in sync by deleting the documents on log out. Then it won't take a query operation to get them. The query's impact on your performance is likely minimal, but this would perform better with a large number of users.
The documentation also has a guide that may be useful: Firebase Docs: Build Presence in Cloud Firestore

How to get user specific data in Firebase Swift 3

I want to retrieve data of current user in the application. How can I do that. ?
Here is my current user's firebase id :
And my table node is :
Here it is clear that my uid and nodes title are different. So how can I get particular user's data.
My code till now:
self.ref = Database.database().reference()
let userID = Auth.auth().currentUser?.uid
self.ref.child("member").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
if !snapshot.exists() {
// handle data not found
return
}
})
You are getting different IDs, because the first one Wnlxl... is the userID and the other -KVvR664... is an autoID.
You have set .childByAutoID following the member, if you want to retrieve the data of the current user then, you have to put userID following member.
Then you can easily retrieve the user's data by userID because each and every detail will be saved under userID.
Hope this code will work for you.
let ref : FIRDatabaseReference!
ref = FIRDatabase.database().reference()
ref.child("member").child(user!.uid).setValue(["name": self.fullName.text!, "email": self.email.text!, "mobile": self.mobile.text!, "doj": self.doj.text!])
Your Firebase screenshot is incorrect I think - your code will work fine, but how you create these members are wrong.
When creating the members you are saying .childByAutoID which you should be using Auth.auth().currentUser?.uid. If that makes sense. Let me know.
Edit: to create a user with userUID data in the node member do the following:
if let userUID = Auth().auth.currentUser?.uid{
ref.child("members/\(userUID)").setValue(*YOURMEMBERINFODICTIONARY*)
}

Retrive node data from firebase database

I have linked my app with a firebase database and i am wanting to retrieve the string of one node from it.
The node I am wanting to retrieve is shown below with the name of 'timeStamp'. Is there a way i can retrieve this text and then print it?
The answer is covered in the Firebase documentation guide
Reading Data
and here's an example:
let ref = FIRDatabase.database().reference()
.child("Users+infomation/ff..etc/timeStamp")
ref?.observeSingleEvent(of: .value, with: { snapshot in
let val = snapshot?.value
print(val!)
})
*this is Swift 3

Resources