Size of child in firebase - javascript

I am using react with firebase realtime database
So i have this firebase data and i want to count total values in followers. However, what i know is that firebase do not have such a function to count and you need to manually do it.
From below i can see all the user data such as username and email. However, i still cannot figure out how to count the number of followers.
I hope someone can help. Thank you.
const ref = firebaseDB.ref();
ref
.child("Users")
.orderByChild("email")
.equalTo(this.state.currentUserEmail)
.once("value", snapshot => {
let userData = {};
for (var childSnapshot in snapshot.val()) {
userData.key = childSnapshot;
// then loop through the keys inside the child object and get the values like price (key) : 44.95 (value)
for (var value in snapshot.val()[childSnapshot]) {
console.log(value);
console.log(snapshot.val()[childSnapshot][value]);
userData[value] = snapshot.val()[childSnapshot][value];
}
}
console.log(userData);
});

Something like this should do the trick:
const ref = firebaseDB.ref();
ref
.child("Users")
.orderByChild("email")
.equalTo(this.state.currentUserEmail)
.once("value", snapshot => {
snapshot.forEach((childSnapshot) => {
console.log(childSnapshot.child("followers").numChildren());
}
console.log(userData);
});
The changes/additions:
Use DataSnapshot.forEach() for a cleaner way to loop over the children.
Use DataSnapshot.child() to get the snapshot for the followers node.
Use DataSnapshot.numChildren() to determine the number of followers.

Related

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

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.

Too many re-renders when accessing data from an API in React

I am making a get request to an API that is linked to my database.
dataApi is a really big object with a lot of objects and arrays nested within it.
Some of the entries from the database are not having the full details that I need so I am filtering them to only show those with a length of > 5.
Now the issue is when I try to get the name of each entry which is split into either Tag1, Tag2 or Tag3.
Before this when I was accessing all the entries and getting the items within them there was no issue.
But when I try to filter them by the name and store the objects corresponding to that name in its state this issue arrises.
Edit:
When I console.log(arr1) it shows all the data but the moment I set the state to it it causes the error.
// Data from all entries in database
const [dataApi, setDataApi] = useState();
// Data for each of the tags
const [tag1, setTag1] = useState();
const [tag2, setTag2] = useState();
const [tag3, setTag3] = useState();
useEffect(() => {
axios.get(URL).then((res) => {
const data = res.data;
setDataApi(data);
});
}, []);
const getTagDetails = data => {
const arr1 = [];
const arr2 = [];
const arr3 = [];
data &&
data.forEach(d => {
// Entries into the database which do not have any tag information
// have a size of 5 and those with all the details have a size of 6
const sizeOfObject = Object.keys(d).length;
// Only need database items with all the details
if (sizeOfObject > 5) {
const name = d["tags"]["L"][0]["M"]["name"]["S"];
// Split the data for the tags into their respective name
// Will be used to set individual datasets for each tag
if (name === "Tag1") {
arr1.push(d);
}
if (name === "Tag2") {
arr2.push(d);
}
if (name === "Tag3") {
arr3.push(d);
}
}
});
setTag1(arr1);
setTag2(arr2);
setTag3(arr3);
};
getTagDetails(dataApi);
I guess the problem is you call getTagDetails(dataApi) inside of file so it causes this infinite rendering problem
Instead remove getTagDetails and try to call this functions after API resolved.
useEffect(() => {
axios.get(URL).then((res) => {
const data = res.data;
getTagDetails(data)
});
}, []);
I think your problem is the way you have structured your getTagDetails function. Each time you render, you call getTagDetails() and the first thing you do is create a new array for each tag. When you call setTag with the new array, it will rerender. You'll probably want to move the getTagDetails logic into the effect so it only runs once on mount (or add a dependency to the dependency array if you need to update on new data)

how to update a map FIRESTORE value with a key JAVASCRIPT

collection name user and a collection name query.
each user document holds a map name seenQueries with string (queryID) : number.
given a user and a queryID (key) i wish to update its number (the value). the rest of the documents fields should remain untouched.
function updateQuerySeen(userID, queryId) {
var userRef = db.collection("users").doc(userID);
var queryRef = db.collection("query").doc(queryID);
const promise1 = userRef.get();
const promise2 = queryRef.get();
Promise.all([promise1, promise2]).then((values) => {
doc1 = values[0];
doc2 = values[1];
curMsgArrayLen = doc2.data().msgArrayLen;
// Uupdate seenQueries map key:queryID
userRef.update({
seenQueries.queryID: curMsgArrayLen; // DOESN'T SEEM TO WORK
}).then(function () {
//console.log("setDocument);
})
.catch(function (error) {
console.error("UPDATE user's seen query failed ", error);
});
});
looked at google API, but it doesn't seem to work https://firebase.google.com/docs/reference/rules/rules.Map
saw this answer Update individual map in cloud firestore document but wasn't sure which one fits my objective, and this one How to update fields in Firestore map didn't work
thank you!

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.

Categories