Retrieving Objects from Firebase using Value() Method - javascript

I cant figure out how to get "value" to read the data in my FB object the same way that the "child_added" does.
The following code:
postNotes.on("value", function(snapshot){
console.log("VALUE FUNCTION REACHED")
var note = snapshot.val();
console.log(note.noteObject);
});
postNotes.on("child_added", function(snapshot){
console.log("CHILDADDED FUNCTION REACHED");
var note = snapshot.val();
console.log(note.noteObject);
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
...displays this in the console:
And here is the data in the FB console:
I don't use any libraries. I would simply like the data from FB to display when my page loads, and continue to update each time new data is pushed to the FBDB.
Am I missing the point of the "value" parameter? What can I do better?
Please forego the answers that involve things such as "read the docs", "use jquery", or otherwise useless answers some StackO users seem to be so fond of.
I've been digging around this problem of mine for a few hours and based on what else I see in StackO a few others have had a similar issue. Thank you so much for taking a look at my question and lending any insight you may have.

You use the same postsRef to listen to both value and child_added events. This is not a common use patterns.
The value event fires when the value of the node changes. So whenever the parent node of -J....NI3 changes, the entire parent node is passed into your callback as the snapshot. If you check the data in the Firebase dashboard, you'll see that this parent node does not have a noteObject child.
Compare that to the child_added event, which fires when a child node is added to the node on which you listen. The callback to child_added in that case gets the new child node passed as its snapshot. And the new child node indeed has a noteObject child.
You'll normally listen to value events on single, lowest-level nodes. When you have a collection of nodes (like you do here), you'll usually use child_added (and its _changed, _deleted and _moved brethren). But just in case you really want to use on('value' with a collection:
postNotes.on('value', function(notesSnapshot) {
notesSnapshot.forEach(function(noteSnapshot) {
console.log(noteSnapshot.val());
});
});
Just be aware that such an approach is less efficient than listening to the various child_ events, especially as you dynamically add or change children in the collection.

Related

How to only read changes in firebase realtime database

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', ...)

Does firebase push method with empty values, just for getting the ID, trigger the child_added event?

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.

Firebase trigger on all collection items while only one has been updated

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.

Firebase: How to use child changed with tables?

I am not sure how child_changed can be used with tables. child_added will work in populating the table but when some change in data occurs, then how to identify which row needs to be updated?
Official documentation suggests child_added to be used with child_changed and child_removed but I'm not sure how the latter 2 will work.
The child_changed event is triggered any time a child node is modified. This includes any modifications to descendants of the child node. It is typically used in conjunction with the child_added and child_removed events to respond to changes to a list of items. The snapshot passed to the event listener contains the updated data for the child.
All I can think of is storing an ID along with the row data, then listening for changes, then getting the ID stored and changing the row data accordingly.
If you are like me then you might use data ID's as keys in your data. EG:
{
"customers":
{
"62562":
{
"name": "Joe blogs"
}
}
}
firebase.database().ref('/customers/62562').on('value', function(snapshot){
console.log(snapshot.val());
});
The above code gives you changes to the data contained in '/customers/62562' but you you won't know where it is from. You need to look at the reference of the snapshot if you wish to know the customerId like:
var customerId = snapShot.ref.key returns '62562'
You can even go further up the branch and find out which branch holds this customer
var parentName = snapShot.ref.parent.key returns 'customer'

How to prevent 'value' event on the client that issued set?

A Firebase client calling set() will cause all connected clients to have value triggered - including - the original client that issued the set().
In my case (and I think in most cases), there is no reason for the client that issued the set() to respond to the value event produced by its own call. Obviously its model is correct and there's no need to change it (which may be an expensive operation).
Is there any way for the client to not-receive/prevent/ignore the value event triggered by its own set() call ? I considered using off/on around set() but that can make the client miss value events that came at the same time but were not triggered by it.
Am I missing something obvious ?
Most applications treat the Firebase data itself as their model. So when there's an update, they call ref.set() (or another mutator function) and then the update flows back into their app through an on() event. React/Flux aficionados know this as a unidirectional data-flow, other might know it as Command Query Responsibility Segregation.
But there indeed cases where the model has already been updated and thus you want to ignore the event from Firebase if you're the one who triggered it.
There is no API for not receiving theses self-triggered events. Instead you'll have to "remember" the data that you sent to Firebase and filter it out in your on() handler.
The Android drawing sample from Firebase keeps a list of segments that it sends to Firebase and then ignores those segments in its onChildAdded handler. It uses push ids to identify the line segments and those are generated client-side, so it can use those to track identify the segments.
A JavaScript sample of this:
var pendingChildIds = []; // Push ids of nodes we've sent to the server, but haven't received in `on()` yet
// this code is in your UI event handler, or whatever triggers the needs to update your Firebase data
var newChild = ref.push();
pendingChildIds.push(newChild.key());
newChild.set(
{ property1: 'value1', property2: 3.14 },
function(error) {
// the write operation has completed, remove the child id from the list of pending writes
pendingChildIds.splice(pendingChildIds.indexOf(newChild.key());
}
);
// this is the event handler, using child_added in this case
ref.on('child_added', function(snapshot) {
if (!pendingChildIds.contains(snapshot.key())) {
// this is a child that we DIDN'T generate
}
});
I ended up adding a client ID to the model, something like:
var clientId=(Math.random()*10000000000000000).toFixed(0);
function set(data) {
ref.set(JSON.stringify({ clientId: clientId, data: data }));
}
ref.on('value', function(snapshot) {
var json=JSON.parse(snapshot.val());
if (!json || json.clientId===clientId) return;
var data=json.data;
// update model with data
});

Categories