Is there any event to listen data on every update whether it is exactly the same data or not?
Let me explain what I want to achieve.
If I set the data as shown below on every 1 second interval
Write Data
setInterval(() => {
firebaseRef.child('liveUser').set({ userId: 1});
}, 1000);
How can I listen liveUser on every update? Right now with my current implementation firebase stop .on('value') event if the value is duplicate.
Read Data
firebaseRef.child('liveUser').on('value', (snapshot) => {
console.log(snapshot.val());
})
I am aware of alternative solution of using timestamp with liveUser object, but it would be helpful if firebase already provides solution for duplicate data.
By design, a listener is only called when data is changed. Writing identical data to the same location does not change the data and thus doesn't trigger attached listeners.
To trigger attached listeners, you need to make a change to the node:
setInterval(() => {
firebaseRef.child('liveUser').set({
userId: 1,
timestamp: Math.floor(Date.now())
});
}, 1000);
Related
i have the following code with Pusher:
Echo.private("channel").listen(".foobar", (e) => {
this.fetchData();
});
When there is an incoming request, I want data to be fetched again. But not on every Pusher event. I want the data to be fetched only once in 5 seconds.
I was thinking about a interval that is reset when there is a new incoming event, but how to achieve this?
Ok, first of all it's a Laravel Echo code. It may be using pusher behind the scenes, but saying it's a pusher code is slightly incorrect.
Then, if I understand you right, you need some kind of debounce function. For example lodash offers one.
const debouncedFunction = _.debounce(() => {
this.fetchData()
}, 5000);
Echo.private('channel').listen('.foobar', e => {
debounced()
})
debounce will create debounced version of function which you can then call, or even cancel, because it comes with cancel method.
debouncedFunction.cancel()
I am using fire store with angular and used onsnapshot method. To remove the listener I did the similar way what docs is suggesting but still I am receiving the real time updates. Any suggestions?
unsubscribe:any;
this.unsubscribe = db.collection("cities")
.onSnapshot(function (){
// Respond to data
});
this.unsubscribe();
I would like to query an API service every 15 seconds, so I can get data from a database and check whether something was changed. If there was a change, then my front end would update automatically because of how vue works.
while (true) {
setTimeout(function() {
QueryService.orders().then(response =>
this.orders = response.data
)
}, 15000)
}
My questions are:
Is this a good approach to solve such a problem at all?
What would be the best position in the code to place such a loop?
EDIT:
Using setInterval() seems to be the right way, but using a polling function with setInterval in the created() hook doesn't affect the data-table at all. It shows me "No data available":
data () {
return {
headers [
{ ... },
{ ... }
],
orders: []
}
created () {
setInterval(function() {
QueryService.orders().then(response => this.orders = response.data)
}, 15000)
}
Using the polling function without setInterval works and fills my data-table with data as usual:
created () {
QueryService.orders().then(response => this.orders = response.data)
}
For a simple and quick solution, I'd go with I'mOnlyVueman's answer. Here some example code I found from Vue.js polling using setINterval(). This example includes
pollData method initiated on created that dispatches a store action (which would call the API)
Canceling the poll as you navigate to another page using beforeDestroy
Code
data () {
return {
polling: null
}
},
methods: {
pollData () {
this.polling = setInterval(() => {
this.$store.dispatch('RETRIEVE_DATA_FROM_BACKEND')
}, 3000)
}
},
beforeDestroy () {
clearInterval(this.polling)
},
created () {
this.pollData()
}
But polling an API isn't very elegant and it doesn't scale well. You'll likely need to do something with Websockets, setting up your app to listen for events pushed from your API.
Here's info on Subscriptions in Vue-Apollo & GraphQL that Denis Tsoi mentioned.
Subscriptions are a GraphQL feature that allows the server to send
data to the clients when a specific event happens on the backend.
Subscriptions are usually implemented with WebSockets, where the
server holds a steady connection to the client. That is, the
Request-Response-Cycle that we used for all previous interactions with
the API is not used for subscriptions. Instead, the client initially
opens up a steady connection to the server by specifying which event
it is interested in. Every time this particular event happens, the
server uses the connection to push the data that’s related to the
event to the client.
A loop like this would go in the component's script within a mounted () lifecycle hook.
That would mean once the component loads your loop would trigger. For detailed guidance on this technique the Vue docs are a good first stop, as well as this article.
I try to get all 10 records using this:
exports.checkchanges = functions.database.ref('school/{class}').onCreate(snap => {
const class=snap.params.class;
var ref = admin.database().ref('/students')
return ref.orderByChild(class).startAt('-').on("child_added", function(snapshot) {
const age=snapshot.child("age");
// do the thing
})
)}
The problem is that after I get the 10 records I need correctly, even after few days when a new record is added meeting those terms, this function is still invoked.
When I change on("child_added to once("child_added I get only 1 record instead of 10. And when I change on("child_added to on("value I get null on this:
const age=snapshot.child("age");
So how can I prevent the function from being invoked for future changes?
When you implement database interactions in Cloud Functions, it is important to have a deterministic end condition. Otherwise the Cloud Functions environment doesn't know when your code is done, and it may either kill it too soon, or keep it running (and thus billing you) longer than is necessary.
The problem with your code is that you attach a listener with on and then never remove it. In addition (since on() doesn't return a promise), Cloud Functions doesn't know that you're done. The result is that your on() listener may live indefinitely.
That's why in most Cloud Functions that use the Realtime Database, you'll see them using once(). To get all children with a once(), we'll listen for the value event:
exports.checkchanges = functions.database.ref('school/{class}').onCreate(snap => {
const class=snap.params.class;
var ref = admin.database().ref('/students')
return ref.orderByChild(class).startAt('-').limitToFirst(10).once("value", function(snapshot) {
snapshot.forEach(function(child) {
const age=child.child("age");
// do the thing
});
})
)}
I added a limitToFirst(10), since you indicated that you only need 10 children.
I have a large data set (~100k entries), that is being subscribed to using the 'child_added' event. Using node 7 and firebase 3.6.1, doing this seems to download the entire 100k entries before a single child_added event is fired.
Memory consumption grows significantly for a few dozen seconds, and then all child_added events are fired swiftly after each other.
This is slow:
require('firebase').
initializeApp({databaseURL: 'https://someproject.firebaseio.com'}).
database().ref('data').
on('child_added', (snap) => console.log(snap.key));
Limiting is still fast (few seconds delay):
require('firebase').
initializeApp({databaseURL: 'https://someproject.firebaseio.com'}).
database().ref('data').limitToFirst(10).
on('child_added', (snap) => console.log(snap.key));
Given the streaming nature of Firebase, I assume it is not intended behaviour for child_added subscriptions to download the entire data set to the client before anything is done.
Am I doing something wrong, or is this a bug?
Although that in the child_added section extracted from firebase documentation it says:
The child_added event is typically used when retrieving a list of items from the database. Unlike value which returns the entire contents of the location, child_added is triggered once for each existing child and then again every time a new child is added to the specified path. The event callback is passed a snapshot containing the new child's data. For ordering purposes, it is also passed a second argument containing the key of the previous child.
At the first lines in that page, we can found this:
Data stored in a Firebase Realtime Database is retrieved by attaching an asynchronous listener to a database reference. The listener will be triggered once for the initial state of the data and again anytime the data changes.
Seems to be its normal behaviour. It first retrieves all the data.
I am in the same situation, waiting nearly 40 seconds for the first child to fire. The only solution I could come up with was to get the keys using Firebase rest API and shallow query parameter, then loop over each key and call Firebase. Here is basically what I did.
`
console.log('start', Date.now());
fetch('https://[firebase_app].firebaseio.com/[your_path].json?shallow=true')
.then((response) => {
return response.json();
}).then(function(j) {
Object.keys(j).forEach(function (key) {
console.log(key, 'start', Date.now());
firebase_reference.child(key).on("child_added", function (snapshot) {
console.log(key, Date.now());
//now you have the first response without waiting for everything.
});
});
});`
I know this doesn't answer your question about child_added functionality, but it does what you would expect to happen with child_added. I am going to submit a feature request to Firebase and link this SO question.