How to retrieve nested data using Javascript (Firebase Realtime Database)? - javascript

I want to retrieve the data from donation and display it in a table. I was able to retrieve the user data from Users and displayed it on a table. But now I don't know how I will be able to retrieve the data from donation.
This is my database structure in Firebase. Note: All of the data that was entered came from a mobile app created in Android Studio.
This is the code that I made when retrieving the User data.
function AddAllITemsToTable(User) {
id=0;
tbody.innerHTML="";
User.forEach(element => {
AddItemToTable(element.uid, element.fullName, element.organization, element.contactPerson, element.contactNo, element.location, element.emailAddress, element.status);
});
}
function GetAllDataRealtime() {
const dbRef = ref(database, 'Users');
onValue(dbRef,(snapshot) => {
var Users = [];
snapshot.forEach(childSnapshot => {
Users.push(childSnapshot.val());
});
AddAllITemsToTable(Users);
})
}
window.onload = GetAllDataRealtime;

Since you're calling onValue on /Users, you already get all data for all users and all of their donations. To process the donations in your code:
const dbRef = ref(database, 'Users');
onValue(dbRef,(snapshot) => {
var Users = [];
snapshot.forEach(userSnapshot => {
Users.push(userSnapshot.val());
userSnapshot.child("donation").forEach((donationSnapshot) => {
console.log(donationSnapshot.key, donationSnapshot.val());
});
});
AddAllITemsToTable(Users);
})
As I said in my comment, I recommend reading the Firebase documentation on structuring data, as the way you nest donations under each user does not follow the guidance on nesting data and keeping your structure flat.

Related

here is my firebase datastructure. how to fetch user data and make table in html

This is the database structure i have i want to get logged in user data.
i want to make table of data: Columns: Date,Status
Also i want to make percentage piechart wheel by calculating success and failure rate. but not able to get data from firebase.
I tried this but not working. I'm able to log in log out successfully. I'm also able to add data in firebase only once per date.
I'm just not able to fetch and show in table.
Here's what i tried:
`
// Get the user's attendance records
firebase.database().ref("attendance").once("value", function(snapshot) {
// Get the attendance data
var attendanceData = snapshot.val();
var userId = firebase.auth().currentUser.uid;
// Display the attendance history
for (var email in attendanceData) {
var attendance = attendanceData[email][userId];
if (attendance) {
for (var date in attendance) {
var status = attendance[date].status;
var tr = document.createElement("tr");
tr.innerHTML = `<td>${date}</td><td>${status}</td>`;
attendanceHistoryTable.appendChild(tr);
}
}
}
});
If I understand correctly, you have a data structure like this:
attendance: {
user: {
"$uid": {
"$date": {
Status: "..."
}
}
}
}
And from this you want to show the status per date for the current user.
If that's indeed the use-case, you can do this with:
const userId = firebase.auth().currentUser.uid;
const attendanceRef = firebase.database().ref("attendance");
const userRef = attendanceRef.child("users").child(userId);
userRef.once("value", function(userSnapshot) {
userSnapshot.forEach((dateSnapshot) => {
const status = dateSnapshot.child("Status").val();
console.log(`User: ${userSnapshot.key}, Date: ${dateSnapshot.key}, Status: ${status}`);
... // TODO: add the data to the HTML as you're already doing
});
});
The main changes I made here:
This only loads the data for the current user, instead of for all users.
This code uses the built-in forEach operation of a DataSnapshot.
This code gives more meaningful names to the variables, so that it's easier to parse what is going on.
This code uses "Status" rather then status, since that's the key in your database screenshot too.

Firestore Delete All References of A User

I have a chat app build in react native. When a user decides to delete their profile, I want to remove all references of them from the database.
The DB has references to their user id in the "matches" table, the "chat" table, and the "messages" table for each of the people the deleted user was chatting with.
I am using firebase functions to handle the deletion of the user doc data and auth but I am not sure what the best way to go about removing all of these references would be. My question is: what is the best way to remove all references of an ID out of a somewhat complex database? I assume this will be taxing to loop through every single user in the DB to search for this one ID.
deleteAccount = () => {
var db = firebase.firestore();
firebase.auth().onAuthStateChanged(async (user) => {
if (user) {
//delete user data
db.collection("Users")
.doc(user.uid)
.delete();
} else {
console.log("user needs to reauth");
return false;
}
});
};
firebase functions
exports.deleteUser = functions.firestore
.document("Users/{userID}")
.onDelete((snap, context) => {
const deletedValue = snap.data();
// Delete the images
try {
admin.auth().deleteUser(deletedValue.id);
const imgRef1 = firebase.storage().ref(user.uid + "/images/0")
? firebase.storage().ref(user.uid + "/images/0")
: null;
const imgRef2 = firebase.storage().ref(user.uid + "/images/1")
? firebase.storage().ref(user.uid + "/images/1")
: null;
const imgRef3 = firebase.storage().ref(user.uid + "/images/2")
? firebase.storage().ref(user.uid + "/images/2")
: null;
imgRef1.delete().then(function() {
imgRef2.delete().then(function() {
imgRef3.delete().then(function() {});
});
});
} catch (e) {
console.log("no images to delete");
}
});
Firebase products such as the databases and storage have no implicit knowledge of what data belongs to what user. That relation only exists because your application code made it.
For that reason you will also have to look up/traverse the relations when deleting the user, to find (and delete) their data. There are no shortcuts in the product here, although there is a open-source library that contains an implementation that works from a configuration file: user-data-protection
Edit: I just realized there's actually an Extension to Delete User Data, which does pretty much the same as the library linked above. It might be worth to have a look if that suits your needs

How to move Firebase relational queries server side

This is my first project with Firebase, and I've created a relational data structure. Now I see why this isn't the best way to do things!
In this part of my app, users can add multiple items to an outfit - here's a diagram of the data structure/relationship I have in Firebase now.
I've included code from a Redux action creator in my React Native app. When a user edits an outfit - removing some items - this code:
takes an array with the new list of items from the client
compares this array with the current saved items server side
creates a new array of the diff (removed items)
loops through the outfits for each of those items, matching against the outfit being edited
removes references that match
This code works, but is pretty deeply nested and messy:
export const updateTagReferences = (localTags, outfitId) => {
//localTags represents the new set of items from application state
//outfitId is the uid for the outfit where those items appear
const {currentUser} = firebase.auth();
return dispatch => {
firebase
.database()
.ref(`users/${currentUser.uid}/outfits/${outfitId}/taggedItems`)
.once('value')
.then(snapshot => {
var serverTags = snapshot.val();
// Work out the diff (ie, which items have been removed locally)
return _.differenceWith(serverTags, localTags, _.isEqual);
})
.then(toDelete => {
toDelete.map(item => {
firebase
.database()
.ref(`users/${currentUser.uid}/items/${item.item.uid}/outfits`)
.once('value')
.then(snapshot => {
var outfits = snapshot.val();
for (var taggedItem in outfits) {
if (outfits.hasOwnProperty(taggedItem)) {
var i = outfits[taggedItem];
return i.uid === outfitId
? firebase
.database()
.ref(
`users/${currentUser.uid}/items/${item.item.uid}/outfits/${taggedItem}`,
)
.remove()
: null;
}
}
});
});
})
.then(console.log('Done'));
};
};
As you can see, I'm trying to use Firebase promises to loop through the outfits nested in each item server side.
My issues are:
I'm making lots of queries to Firebase, which isn't ideal
console.log('Done') fires before .remove() - I need to follow up with a second action once this action completes
I've tried the following code, based on this answer, but I can't seem to get it to work:
export const updateTagReferences = (localTags, outfitId) => {
const {currentUser} = firebase.auth();
return dispatch => {
// Create a ref for the outfit the user is editing
firebase
.database()
.ref(`users/${currentUser.uid}/outfits/${outfitId}/taggedItems`)
.once('value')
.then(snapshot => {
// Compare local (app state) with remote (Firebase) to work out which items have been removed
var serverTags = snapshot.val();
return _.differenceWith(serverTags, localTags, _.isEqual);
})
.then(toDelete => {
var promises = [];
// Create a ref for each item to delete
toDelete.map(item => {
firebase
.database()
.ref(`users/${currentUser.uid}/items/${item.item.uid}/outfits`)
.once('value')
.then(snapshot => {
var outfits = snapshot.val();
for (var taggedItem in outfits) {
// Loop through the outfits that item appears in
if (outfits.hasOwnProperty(taggedItem)) {
var i = outfits[taggedItem];
// Match against the outfit the user is editing
return i.uid === outfitId
? promises.push(
firebase
.database()
.ref(
`users/${currentUser.uid}/items/${item.item.uid}/outfits/${taggedItem}`,
)
// Remove the reference
.remove(),
)
: null;
}
}
})
// Execute all the promises, removing firebase references for each item removed locally
.then(Promise.all(promises).then(console.log('Done')));
});
});
};
};
I'm trying to make my code more efficient overall, so I can replicate it elsewhere in my project. I'd love an explanation of the best way to move this kind of query server side.
Currently, changing the whole data structure is out of scope (that's for next time!)
Thanks.

Retrieving data on firebase having child key uid (javascript)

I am struggling how to retrieve data from firebase having a child key, such as uid.
here is the structure of my firebase.
Currently I am making an admin panel which can read the order placed by each user and render it through flatlist in react native, but it seems that I can't access their order because every time the user places an order it is stored on their unique User.id
I don't know how to make a reference to the User.id child like firebase.database().ref(orders/${AllUserId}/products)
You can use forEach loop to fetch ids and can get values as so
firebase.database().ref('order').on('value', (snapshot) => {
snapshot.forEach((child) => {
uid = child.key; // gives uid1
child.forEach((snap) =>{
var id = snap.key; // first iteration gives uid2
firebase.database().ref('order/'+uid+'/'+id).on('value', (snapchild) => {
snapchild.forEach((snapshotchild) =>{
console.log(snapshotchild.val());
});
});
});
});
});
This could be more insightful.

Retrieve multiple data from firebase database in one cloud function

I am faced with the problem of retrieving two data values of a single node from my firebase database and reference it in my javascript file but don't know how to go about it. I have been able to retrieve just one data value from a node (in this case "message") but I would like to add "from" as well. Most tutorials just reference one so I am really confused. So how do I get multiple data values?
This is my code...
JS file
exports.sendNotification7 = functions.database.ref('/GroupChat/{Modules}/SDevtChat/{SDevtChatId}/message')
.onWrite(( change,context) =>{
// Grab the current value of what was written to the Realtime Database.
var eventSnapshot = change.after.val();
var str = "New message from System Development Group Chat: " + eventSnapshot;
console.log(eventSnapshot);
var topic = "Management.Information.System";
var payload = {
data: {
name: str,
click_action: "Student_SystemsDevt"
}
};
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToTopic(topic, payload)
.then(function (response) {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent message:", response);
return;
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});
You can read from however many nodes you want in a Cloud Function. However, only one can trigger the function to run.
To read from your database use the following code:
admin.database().ref('/your/path/here').once('value').then(function(snapshot) {
var value = snapshot.val();
});
You will probably want to read from the same place that the Cloud Function was triggered. Use context.params.PARAMETER to get this information. For the example you posted your code would turn out looking something like this:
admin.database().ref('/GroupChat/'+context.params.Modules+'/SDevtChat/'+context.params.SDevtChatId+'/from').once('value').then(function(snapshot) {
var value = snapshot.val();
});
Just trigger your function one level higher in the JSON:
exports.sendNotification7 =
functions.database.ref('/GroupChat/{Modules}/SDevtChat/{SDevtChatId}')
.onWrite(( change,context) =>{
// Grab the current value of what was written to the Realtime Database.
var eventSnapshot = change.after.val();
console.log(eventSnapshot);
var str = "New message from System Development Group Chat: " + eventSnapshot.message;
var from = eventSnapshot.from;
...

Categories