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', ...)
Related
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.
Reading firebase real time database docs it is not clear when the child_added event triggers exactly. It says it triggers when a new child is added to a node, so far so good. The docs also say that, if you want to get the next available unique Id on a path, you just call push() on that path to get a reference that will have a unique ID. However, it is not clear if this empty push call will be considered an event of child_added or if it will be ignored. Once you get the ID, you can not push again or you will get another ID (that is just my guess) so you just set the given reference with the data you want it to contain. It is not clear either if this last operation will trigger a child_added event.
Let me ilustrate with a bit of code with inline questions:
const dbRef = db.child('todos')
const newTodoRef = dbRef.push() // does this trigger child_added event?
newTodoRef.set({ id: newTodoRef.key, name: 'test' }) // and does this?
Calling push() without any arguments does not write any data, so it does not trigger any events yet. It merely creates a reference in the code to a new unique location.
Calling set(...) on this reference does then write data, so does trigger events.
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.
Every time I do an update with the same object(s3) with same values and properties, Firebase trigger the event 'child_added' even if there's nothing to add or update.
I made some test by modifying on the firebase console some values in subcollection of the main object and noticed that it returns a snapshot with the first element correct and then all the other elements of the collections as 'ADDED' elements. This is not true because the collections didn't change except the one on which I performed an action.
I just need that when I send the same identical object that is stored on the db, firebase will recognize smartly that no action is requested and no trigger need to be activated.
var studentiRef = ref.child('studenti/' + s3.matricola);
studentiRef.update(JSON.parse(JSON.stringify(s3)));
studentiRef.on("child_changed", function(userSnapshot) {
var tasseRef = userSnapshot.ref.child('tasse');
tasseRef.on('child_added', function(itemSnapshot, prevKey){
console.log('ADDED ON');
console.log(itemSnapshot.key)
})
});
studentiRef.on("child_changed", function(userSnapshot) {
userSnapshot.ref.child('tasse').on('child_removed', function(itemSnapshot, prevKey){
console.log('REMOVED ON');
console.log(itemSnapshot.key)
})
});
studentiRef.on("child_changed", function(userSnapshot) {
userSnapshot.ref.child('tasse').on('child_changed', function(itemSnapshot, prevKey){
console.log('CHANGED ON');
console.log(itemSnapshot.key)
})
});
UPDATE:
Before posting update I made some experiments with no successful results.
Here the pics of the console, the database and the code.
Going nuts on this.
Here three screenshot: 1 firebase data 2 snippet 3 console log
UPDATE II:
scenario
behaviours on modifying value in firebase
SOLVED:
By getting inspired from the github firebase examples, I found out a common mistake in using firebase: i was not flatting the data.
To continue using my data structure (a root object within a list of objects), the solution was to trigger an update of every single object (pseudocode: ref.update(root/childobject) n-times instead of ref.update(root).
If someone else ran into this problem, I will explain better.
Always, FLAT YOUR DATA! (using firebase)
Most likely these events come directly from the client SDK, which doesn't detect if there was an actual change. The database server does perform such a check, and will only send out changes to other clients if there was an actual change.
Update:
The Firebase client + server behave in the following way when you're calling telling it to update a node to its current value.
The client fires the local event(s) to reflect the update. So child_changed will fire.
The client send the update to the server. This is needed since the client and server may be (slightly) out of sync, and the server is the single-source-of-truth.
The server compares the update with the current value of the node. If it is the same, the process stops here.
If the updated value is different from the current value and passes validation/permission checks, the data is committed to disk and broadcast to any active listeners.
If the updates value is different, but rejected by the validation/permission checks, the servers sends a rejection message to the original client, which then fires another child_changed event to revert the local change.
I am trying to imitate an insertion trigger on Firebase using the onWrite method. The insertion is done via POST requests since I am testing it (easiest way I found to check database triggers). The trigger includes writing the Firebase generated ID inside the inserted data as a new property.
My cloud function is this:
exports.onNewSeries = functions.database.ref('/series').onWrite(event => {
"use strict";
console.log(event.data.key);
console.log(event.data.current.key);
console.log(event.data.current);
});
Both first logs contain the same key (series), which actually is the key of the parent node where the new data is appended, instead of the new data key (in the quirky form of -adfaa123sdfasdf). The last log prints a Firebase structure containing the new data as well as the generated key in a _data property, however it is not accessible.
While this can be done manually after a request, I have not seen it automated in a database trigger way.
To get the generated key, make the function trigger on a specific child:
exports.onNewSeries = functions.database.ref('/series/{id}').onWrite(event => {
console.log(event.params.id);
});
Also see the Firebase documentation on handling database events.