Firebase Query Returns Empty Array even though there are objects in the endpoint
Description
The firebase-query element's data observer method, which has parameters newData and oldData returns an empty array, preventing transformation of the data in the observer.
Expected outcome
I have an observer _onDataReceived(newData, oldData) function that gets called on change of a firebase-query's data property. This data is retrieved from a path that only has two items.
I expected the observer function to return an array of two items so that I can transform it in the observer method.
Actual outcome
What actually happens when stepping through observer method is that it gets called two times, but both times newData is an empty array. However, the observer method console.log's newData both times, and running the observer method without breakpoints shows that the second time the observer method gets called, newData is an array of two objects.
The code is run as if there is no data in newData (both times newData is an empty array)
Steps to reproduce
- create a firebase app with an endpoint /test2 that has two objects in it.
-
create a
firebase-testelement:
<link rel="import" href="/bower/polymer/polymer.html">
<link rel="import" href="/bower/polymerfire/firebase-auth.html">
<link rel="import" href="/bower/polymerfire/firebase-app.html">
<link rel="import" href="/bower/polymerfire/firebase-query.html">
<dom-module id="test-firebase">
<template>
<firebase-app auth-domain="YOUR_AUTH_DOMAIN"
database-url="YOUR_DATABASE_URL"
api-key="YOUR_FIREBASE_API_KEY">
</firebase-app>
<firebase-auth id="firebaseAuth"
location="YOUR_DATABASE_LOCATION"
user="{{user}}">
</firebase-auth>
<firebase-query
path='/test2'
data="{{data}}">
</firebase-query>
</template>
<script>
Polymer({
is: "test-firebase",
properties: {
data: {
type: Object,
observer: '_onDataReceived'
}
},
_onDataReceived: function (newData, oldData) {
console.log("objects in newData:", newData);
this.convertedData = [];
for (item in newData) {
this.push('convertedData', { 'id': item});
}
console.log('convertedObjects', this.convertedData);
}
});
</script>
</dom-module>
- Put a
firebase-testelement in the page. - Open the page in a web browser.
- Inspect Element and look at console.
- Add a breakpoint at
console.log("objects in newData:", newData); - Refresh page and step through both invocations of the observer method. Notice the value of
newData - remove breakpoint.
- refresh page. Keep eye on console log.
- Notice the value of the second log of
newData. The two objects magically appear even though they weren't initially there in the step through and the observer method.
I tried the data.splices workaround (https://github.com/firebase/polymerfire/issues/67), but that retrieves the same data from firebase following this pattern: retrieves an array of size 1, then an array of size 2 (object 1 and object 2), then an array of size 3 (object 1,2 and 3) etc.
This unnecessarily retrieves the same data multiple time, resulting in a long load time.
-->
Browsers Affected
- [ X] Chrome
#67 is not a workaround but how Polymer really works.
firebase-query uses this.push('data', {value of child added}) to the data attribute. This is because if we use this:
this.data = [];
var newArr = [];
for (var i in dataLoaded) {
newArr.push(dataLoaded[i])
}
this.data = newArr;
Then you will have a constant flicker of an array with no elements then an array of 1, 2, 3, 4, 5 elements every time a child_added event is being called.
Even if we change the behavior of "observer" to allow detection of object.splices, it will still have that same behavior of having an array of object 1, then 2, then 3, then 4 because of how firebase (not polymerfire) work in sending frames to your browser.
What you can do is you can use the value used in the limit-to-start or limit-to-end attribute of firebase-query, and use a condition that if data.length >= limitValue then you just start running the function.
I'm having the same problem. I was wondering what version of Polymer you're using?
Did you load the firebase-database-script.html along with the firebase-app-script and firebase-app?
On Sat, 5 Nov 2016 08:13 Mark Fortner, [email protected] wrote:
I'm having the same problem. I was wondering what version of Polymer you're using?
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/firebase/polymerfire/issues/126#issuecomment-258576812, or mute the thread https://github.com/notifications/unsubscribe-auth/AChe1jSQY5KK1ULuiWRMoZPn_zYG16KDks5q68oigaJpZM4KILRW .
@tjmonsi I must have missed that in the documentation. I've loaded the polymerfire.html element which is supposed to have all of the dependencies that you need.
I think it was not in the docs either. I just figured it out while debugging my simple code as to why firebase query and firebase document doesnt work
On Sun, 6 Nov 2016 01:32 Mark Fortner, [email protected] wrote:
@tjmonsi https://github.com/tjmonsi I must have missed that in the documentation. I've loaded the polymerfire.html element which is supposed to have all of the dependencies that you need.
— You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/firebase/polymerfire/issues/126#issuecomment-258628335, or mute the thread https://github.com/notifications/unsubscribe-auth/AChe1pGQUNlvaosHX1OwE5BSn_zLuep0ks5q7L3HgaJpZM4KILRW .
If they add it to the docs it will definitely clear up some confusion. Better yet, have all dependencies in the element.
I think i understand the idea of not putting in all the scripts when you only need is auth or database and not storage and messaging. But if you really need it all, you can just import poylmerfire/firebase.html before importing polymerfire/firebase-app
On Sun, 6 Nov 2016 09:12 Mark Fortner, [email protected] wrote:
If they add it to the docs it will definitely clear up some confusion. Better yet, have all dependencies in the element.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/firebase/polymerfire/issues/126#issuecomment-258653504, or mute the thread https://github.com/notifications/unsubscribe-auth/AChe1gKQQS1ThXMfNeYTUFKRRNt0n6Qxks5q7SmXgaJpZM4KILRW .
Apparently though, these are required dependencies and are needed in order for the elements to function. The browsers automatically cache the imports so duplicate references don't cause a performance hit.
But the ordering of import also matters... Like when i loaded firebase-auth-script before firebase-app doesnt work.
And if you have initialized firebase-app before lazy loading a page that has firebase-document which in turn loads firebase-database-script, it somehow doesnt work
On Sun, 6 Nov 2016 09:19 Mark Fortner, [email protected] wrote:
Apparently though, these are required dependencies and are needed in order for the elements to function. The browsers automatically cache the imports so duplicate references don't cause a performance hit.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/firebase/polymerfire/issues/126#issuecomment-258653721, or mute the thread https://github.com/notifications/unsubscribe-auth/AChe1icWg4wx3ycOIcLgVHw8kqxMDtDRks5q7SsygaJpZM4KILRW .
I can help address this.
On Sat, Nov 5, 2016, 6:27 PM Toni-Jan Keith Monserrat < [email protected]> wrote:
But the ordering of import also matters... Like when i loaded firebase-auth-script before firebase-app doesnt work.
And if you have initialized firebase-app before lazy loading a page that has firebase-document which in turn loads firebase-database-script, it somehow doesnt work
On Sun, 6 Nov 2016 09:19 Mark Fortner, [email protected] wrote:
Apparently though, these are required dependencies and are needed in order for the elements to function. The browsers automatically cache the imports so duplicate references don't cause a performance hit.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub < https://github.com/firebase/polymerfire/issues/126#issuecomment-258653721 , or mute the thread < https://github.com/notifications/unsubscribe-auth/AChe1icWg4wx3ycOIcLgVHw8kqxMDtDRks5q7SsygaJpZM4KILRW
.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/firebase/polymerfire/issues/126#issuecomment-258653977, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAD_jpFreEV3CPVbby3CSQ0Wk2zqNoPks5q7S0PgaJpZM4KILRW .
@tjmonsi The issue with the limit approach for my use case is that the data at an endpoint can range from 2 points to thousands of points. So if I set an "at least" limit before running the array pushing function, I miss out on all the endpoints where there might not be that many points.
Additionally, setting the "at least" limit to a smaller number will still take a long time to load due to the dataLoaded loading 1, then 2, then 3 etc.
I have also added the two script files and the loading is still very long. It takes me 4-5 seconds to load an endpoint with 200 data objects.
I am confused as to how this is a firebase issue because another client application using the mobile firebase sdk is obtaining the same data almost instantly.
@ahilans I think what I can suggest is not to use the firebase-query because it uses the child_added event rather than the value event. If you are not adding a limit value and you want to load everything inside the endpoint, you can just use firebase-document.
<firebase-document
path="/test2"
data="{{data}}"
></firebase-document>
then in your script do this:
observers: [
'_onDataReceived(data.*)'
]
_onDataReceived: function() {
var newData = this.data;
var convertedData = [];
for (var item in newData) {
convertedData.push({ 'id': item});
}
this.convertedData = convertedData;
console.log('convertedObjects', this.convertedData);
}
This would instantaneously (I hope) show the data. The slow down would be of course if you have a thousand points in an endpoint which is caused by the latency of loading a lot of points
Basically the whole example reported in https://beta.webcomponents.org/element/firebase/polymerfire/v0.10.3/firebase-query doesn't work. Since no change in {{data}} is detected then the list of < sticky-note > is not updated. I think this is a big issue.
@mbleigh can you comment on the dependency ordering questions above?
There was another report on slack that importing firebase-app in one file and then importing firebase-auth and firebase-query (for example) in a second file (child element) wasn't working. However, this is approximately what the demo does.
If there's an ordering dependency here, it's not apparent from the docs.
i changed all data to _data & add _data in properties
_data: {
notify: true,
},
now it's working, all result getting in _data
@arthurevans I think it is a case of a race-condition. I have experienced it and come up with my own personal solution...
Apparently, importing the firebase-app only imports firebase-app-script.html, which imports the firebase.js shell script. But because you didn't import the firebase-auth.js and firebase-database.js files, initializing firebase-app doesn't do anything.
That means even if you have imported firebase-auth, which in turn imports firebase-auth-script.html; and firebase-query, which in turn imports firebase-document-script.html, it was only imported after you have initialized firebase-app...
Here's what is happening i think...
// parent-element
<link rel="import" href="bower_components/polymerfire/firebase-app.html">
<link rel="import" href="child-element.html">
...
<firebase-app ... ></firebase-app>
<child-element></child-element>
// child-element
<link rel="import" href="bower_components/polymerfire/firebase-app.html">
<link rel="import" href="bower_components/polymerfire/firebase-query.html">
...
<firebase-auth></firebase-auth>
<firebase-query></firebase-query>
Sequence
- parent-element is loaded and parsed
- parent-element is executed
- firebase-app is loaded
- child-element is loaded
- firebase-app is parsed and executed through call of firebase-app element
- child-element is parsed and executed
- firebase-auth is loaded
- firebase-query is loaded
- firebase-auth is parsed and executed through call of firebase-auth element
- firebase-query is parsed and executed through call of firebase-query element
I have bumped into this issue as well, though it's probably because I'm using firebase-query in an unexpected way.
I'm currently simulating typeahead with firebase query using the following code:
<firebase-query
id="game-query"
app-name="games"
limit-to-first={{resultSize}}
order-by-child="name"
start-at="{{gameName}}"
end-at="{{gameName}}zz"
path="/games"
data="{{data}}">
</firebase-query>
In this case, gameName is input from the user in a search box. Generally speaking, this actually works quite well. The problem is I want to animate the creation of the children, which requires me to know when firebase-query has returned all of it's results.
Should I be using something other than firebase-query for this? I still have not come up with a workaround. This currently causes other problems such as preventing me from being able to ignore "the" in the name of games or handle case sensitivity. I'm extremely open to other approaches. I'm clearly not a firebase expert.
i have the same problem
With an empty array being outputted, how can I count the number of objects in the data of firebase-query element?
It's not only empty, but I can't even access smth like data[0]. Any fix or workaround?
I'm experiencing the same issue. The observer on the data received from Firebase is fired up and I get an empty array first, then the observer is fired up a second time with the right data from the database. It's quite a problem for implementing a loader for exemple.