I am trying to access the child value of a unique key value (that had been "pushed") within Firebase. Currently, my database looks like this: I want to access the value of "emailOfUser"
I am very new to Firebase so I am not familiar with the functions. Currently, this is my method of obtaining other values for a different section of the database:
Thank you so much for any feedback!
I've tried different methods to accessing this data within the Firebase, but I cannot get it to work/the methods I were using were outdated. I also tried to "update" the Firebase instead of "pushing" the values to prevent a unique key from generating, but it simply overwrote my current data rather than appending something new.
If you want to load all the users who voted and print their emails, you can do that with:
get(child(dbref, 'usersWhoVoted')).then((snapshot) => {
snapshot.forEach((childSnapshot) => {
console.log(childSnapshot.key, childSnapshot.val().emailOfUser);
});
})
Note that your current structure allows a user to vote multiple times. If you want to only allow them to vote once, use some identifier of the user as the key in your database structure:
userVotes: {
"uniqueIdOfUser1": "valueTheyVotedOn",
"uniqueIdOfUser1": "valueTheyVotedOn",
...
}
Now each user can by definition only vote once, If they vote again (assuming your security rules allow that), their new vote will simply replace the existing vote.
Related
I am creating a sns-like web application, and trying to implement a "liking a post" function. Basically each post has data in firestore, such as the caption of the post, the image of the post, number of likes on the post and etc. What I want to do is, if a user clicks a like button on any post, the number of likes on the post clicked will be incremented by 1. However, I do not know how I can restricting each user can like only one time on each post. My current code works for incrementing the number of likes but the user can like a post as many times as the user clicks.
I am totally a beginner in firebase, react and javascript and would be really appreciated for any help. Thank you.
here is my code working for incrementing a number of likes.
const likeHandle = async () => {
const docRef = doc(db, "posts", postId);
await updateDoc(docRef, {
noLikes: noLikes + 1
});
}
You won't be able to do this at scale inside the same document where you are tracking the number of likes, because there is a max size to each document.
What you will have to do instead is store a record of each pair of user and like in its own document in a separate collection, and check to make sure that any new like requests are not already represented in that other collection. Your UI should also probably disable likes if there is a record for that pair of user and post so that the user is not presented with an option that you don't want them to take.
There is no direct way to limit how often a user can write a specific piece of data.
What you can do however is:
Add a usersWhoVoted field with UIDs to the document, or a userWhoVoted subcollection under it.
Write both the increased number of likes and the UID to the database in one operation (using a transaction/batched write if you chose a subcollection).
Use security rules that only allow the user to increment the count if they also added their UID in that operation, and only decrease the count if they removed it (if that is also a use-case you want to support).
You should probably also use the atomic increment operation, to prevent depending on client-side state that can be outdated (although your security rules should catch and reject that situation anyway).
I have a database collection with readings, each new reading needs to be checked if it's out of the ordinary, if it is, there needs to be an alert sent.
So i'm using db.ref('collection').on('child_added', (child => { check(child); });
The problem with the .on function is that when the listener is added, all previous data is also read.
So how do i read a collection that only reads the changes in the database, also when the listener is first added? Or if that doesn't work, how do I differentiate the already added data with the new data?
The Firebase database synchronizes the state of whatever query or reference you attach your listener to. There is no option to only get new nodes built into the API.
If you want only new nodes, you will have to:
Ensure each node has an associated timestamp or order. If you're using Firebase's built-in push() keys, those might already serve that function.
Know what "new" means to the client, for example by either keeping the last timestamp or push key that it saw.
And then use a query to only request nodes after the stores timestamp/key.
So for example, if you only want to read nodes that are created after the moment you attach the listener, you could do something like this:
let now = db.ref('collection').push().key; // determine current key
db.ref('collection').orderByKey().startAt(now).on('child_added', ...)
Is there an out-of-box/best-practice solution to retrieve a user object from the Updated By (sys_updated_by) field on the Incident/Task table?
I know a workaround would be to create a custom field on Task pointing to the User table, type Reference. Then create a custom business rule to set the field on "Insert/Update". Is this the only way?
current.sys_updated_by does not reference further User data of who updated the record. current.sys_updated_by is a string value that contains the string value originating from user_name.sys_user on the sys_user table.
It is however possible to use "current.sys_updated_by" with in your Notification or business rule to get further information of the user that updated the record
this can be done by executing another glide query with in the Mail script/Business Rule/Notification etc.
For example:
var userdata = new GlideRecord("sys_user");
userdata.addQuery('user_name', current.sys_updated_by);
userdata.query();
while (userdata.next()) {
var email = userdata.email; // Will give you the email of the user
}
Where "userdata" is the array values for the entire user record.
You need to put your question in context. What are you trying to accomplish?
If you are in a server script (e.g. Business Rule) then it is quite easy. If current is your GlideRecord for Task or Incident, and you need a GlideRecord for sys_user then the code is.
var grUser = new GlideRecord('sys_user');
if (grUser.get('user_name', current.sys_updated_by)) {
// do something with grUser
}
If you have reporting needs that require you to drill through to pick up user attributes of the last person who updated a task, then you can add a custom field to the Task table and maintain it with a Business Rule.
As a side note, there is a reason why sys_updated_on is not a sys_id. It is possible that the last person to update an object is not a user in your instance. They could have been a user in another instance and the object was updated in your instance via XML or an Update Set.
I have data model like this
Players-->root collection
Sports--->root collection
Players_Sports---root collection
I want get all the sports(Multiple sport) details or document player belongs.
For this I am using angularFireStore5
First, I am getting
Player details like this
this.db.collection('players').doc(id).get().toPromise()
Second, I am getting Player(user) linked PlayerSport
db.collection<any>('PlayerSports',ref => ref.where('playerId', '==', id) ).get().toPromise()
Third, I am trying to get Sports details based on ID'S,
db.collection<any>('sportsType', ref => ref.where('sportsType' 'in' [sportsIDs])).get().toPromise()
where SportIDs is arrary of ID that are linked in player_sports
First and Second steps works fine, but third steps is not giving any data or response
Could you please let me know where is the problem,
is it in Data model or code? my guess is that data model is not correct. Please guide me on this.
I would suggest getting the data from firebase and storing it inside a list so the app can access it later.
void getDataF(){
databaseReference
.collection("TableName")
.getDocuments()
.then((QuerySnapshot snapshot) {
snapshot.documents.forEach((f) {
iDFacList.add(f.documentID);
dbFacList.add(f.data["FieldName"]);
});
});
}
There is no sportsType field in the sportsType document as far as I can see.
If you're trying to find documents based on their SportsId field, you'll want ref.where('SportsId'....
Update
It seems that you're trying to find a document by its ID, which you can do with:
ref.doc(sportsIDs)
If you want to get multiple documents, or get a single document as a collection, you can use:
ref.where(firebase.firestore.FieldPath.documentId() 'in' [sportsIDs])
I am using firebase and want to loop through my messages that I have and delete certain ones based upon a user's uid.
Here is an image of what I have for the structure of my data:
So far I know you would start of as something like:
Firebase.database().ref('messages').on('value', snapshot => {
snapshot.forEach(snap => {
if(snap.val().user.id === currentUser.uid){
//delete message here
};
});
});
Where do I go from here?
First of all, you probably want to use once() instead of on(). If you modify the contents of the database that you're working with, your on() will get triggered again for each change. You can see how that might be problematic for your case, if you only want to loop through the data once. Definitely learn about the difference between once() and on().
If you have a DataSnapshot type object, you can delete the contents of the database at its location with
snap.ref.remove()
Definitely read up on the Reference object type.