I'm new using firebase and I'd like to make an infinite scroll pagination to my posts.
Suppose I have this post IDS:
-M5HMGs3EnBv6O2NSxG
-M5HMGsA3YyW_NJ3fSV
-M5HMGsdfLOOEPPBR_s
-M5HMGsiH9HIZw9DNaz
-M5HMHFYoUX8kNolLrP
-M5HMHFZvDrV27S2hSt
-M5HMHFnrQ_l4mVQ0rX
-M5HMHFoaV8wbexwPCd
-M5HMJQaaFGxF450lJB
-M5HMJQe319R19Cvak6 // THE LAST ONE IN FIRST PAGINATION
-M5HMJQh2gWuah7GSht
-M5HMJQlrcfTTF3fbbI
-M5HMJQo6QT1HwWP2lz
-M5HMJQrIUiZyzhiqK3
-M5HMJQudSkFdvs42D1
-M5HMJRCmbFbxKp1NgA
-M5HMJRFwfo7yN8Is3-
-M5HMJRIsKT3YmoukQ0
-M5HMJRKDTq7XuqtshT
-M5HMJRNRabXbYQUMi6
-M5HMJRS1t9UBzH_3Jh
-M5HMJRXEv6BaPeQPMn
-M5HMJR_bRdxCBy-uma
-M5HMJRdOPBA-SMoMjB
So, first I get the first 10 posts till the id M5HMJQe319R19Cvak6 using this:
var starCountRef = firebase.database().ref('/posts/').limitToFirst(11);
it is ok. When I go to the last post my reactjs will call this function again sending the last loaded post ID (the M5HMJQe319R19Cvak6) in variable pageNumber.
What I'd like to do is get posts after this last id given to continue the pagination, like so:
-M5HMJQh2gWuah7GSht
-M5HMJQlrcfTTF3fbbI
-M5HMJQo6QT1HwWP2lz
-M5HMJQrIUiZyzhiqK3
-M5HMJQudSkFdvs42D1
...
I tried to use startAt(ID) but no result has shown:
var starCountRef = firebase.database().ref('/posts/').limitToFirst(11).startAt(pageNumber);
any ideas how can I get posts after an id in firebase?
Firebase Realtime Database queries consists of two steps:
You call one of the orderBy methods to order the child nodes on a specific value.
You then call one of the filtering methods (startAt, endAt, equalTo) to determine where to start and stop returning data.
Your code does that second step, but fails to do the first step. This means that you're using Firebase's default sort-order, which is by each node's priority. Priorities are a left-over from the days then this API didn't have any better sorting options. These days, you'll always want to call orderBy... before filtering.
With that knowledge, your query for getting the second page of results should look something like:
firebase.database()
.ref('/posts/')
.orderByKey()
.startAt("-M5HMJQe319R19Cvak6")
.limitToFirst(11)
I highly recommend calling the "-M5HMJQe319R19Cvak6" value something else than pagenumber as that variable name makes it seem as if Firebase queries are offset-based, which they aren't.
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.
I want to read last message node as shown in image below.
I am using below query to retrieve last message where suid and ids are known(as shown in img). but not working.
firebase.database().ref("Messages/"+suid).child(ids+"/chat").orderByKey().limitToLast(1);
How to retrieve last message from firebase realtime db and display it to my console? Thanks
Your existing code looks fine, so let's store that query in a variable first:
const query = firebase.database().ref("Messages/"+suid).child(ids+"/chat").orderByKey().limitToLast(1);
Now you can read the message(s) this query matches with either once() or get(). I'll use once(), since it's much older and hence you're more likely to find examples of it elsewhere:
query.once("value").then((snapshot) => {
snapshot.forEach((message) => {
console.log(message.val().message.msg);
});
})
Some things to note here:
Since a query may have multiple results, the snapshot contains a list of those results. Even if there's only a single result (like here), the snapshot is a list of one result. To loop over these results, we use snapshot.forEach().
Your msg is nested under message in each child, so we use message.val().message.msg to get at its value.
Assuming I have 1000+ blog posts. What will be the best practice to get data from firebase using axios to store in nuxtServerInit?
Can I somehow get the first 10 blog posts first during the first load and get even more data later on?
Right now I have vuex action as following:
nuxtServerInit(vuexContext, context) {
return axios
.get('https://my-blog.firebaseio.com/posts.json')
.then(res => {
const postsArray = []
for (const key in res.data) {
postsArray.push({ ...res.data[key], uid: key })
}
vuexContext.commit('setPosts', postsArray)
})
.catch(e => context.error(e))
},
You're using the REST API to access the Firebase Database. To retrieve a limited number of items, use a limit query.
https://my-blog.firebaseio.com/posts.json?limitToFirst=10
Since a limit only makes sense when you know how the items are order, you'll want to also order the items, i.e. on their key:
https://my-blog.firebaseio.com/posts.json?orderBy="$key"&limitToFirst=10
Note that the results may not be ordered, since the order of properties in a JSON object is undefined. So the result will contains the first 10 posts, but it may not show them in the right order.
Next step is to get the next 10 items. Unlike on most traditional databases, Firebase doesn't support an offset clause on its queries. So you can't tell it to skip the first 10 items to get to the next 10.
Instead Firebase queries use anchors/ranges: you must know the last item of the previous page to build the query for the next page. Say that the 10th post had a key of keyOfPost10, then you can get the next page with:
https://my-blog.firebaseio.com/posts.json?orderBy="$key"&startAt="keyOfPost10"&limitToFirst=11
We need to retrieve 11 posts here, since we're also getting the 10th post. That also means you'll need to filter the overlapping post in your client code.
I know I haven't got any code example, but it's due to the fact that I'm unsure on how to proceed.
I'm building a site with jQuery and Bootstrap, and are going to display a list of around 7000+ items.
I'm using $.getJSON(...) to get the list of items from my PostgreSQL database. This call goes pretty quick.
I would like to create a list which is capable of typeahead search/filter, where elements are displayed corresponding to a user is typing.
I'm not interested in calling my PostgreSQL database more than once - if possible - but would also like to not to kill the browser with DOM elements etc.
What are the best way to proceed, are there any existing components in Bootstrap or...?
ForerunnerDB would be a good library to use: http://forerunnerdb.com/
It's a client side NoSQL db. You'll be able to insert your data into a collection and create a view which can handle auto binding of the data to the DOM. Loading over 7000 DOM elements is a big task, lazy loading is probably the way forward for you; my suggestion would be to display 100 records at a time and when the user is close to the bottom of the list trigger more DOM elements to be rendered:
//Take data from a collection, query it to build a view, and link it to the DOM
db.view('dataView')
.query({
/*
* Filter documents in the collection
* calling db.view('dataView').find() will now only pull records from the 'data' collection which contain a key `verified` that have the value 'true'
*/
verified: true
})
.queryOptions({
//Apply options
//calling db.view('dataView').find() will limit the result to the first hundred records
$limit: 100
})
.from('data')
.link('#targetElement', 'templateName');
To unlink the view again call db.view('dataView').unlink().
When you want to render more records, simply do the following:
var query = db.view('dataView').query();
query.$limit += 100;
db.view('dataView').query(query)
This will automatically render the next hundred records.
Using a combination of .query({}) and .queryOptions({}) will allow you to manipulate the view's data pretty much any way that you want, I've been able to build some complex filtering and searching with ease using this technique.
Question related somewhat to: Ember.js: retrieve random element from a collection
I've two routes: randomThing route and things route.
The former displays a... random thing from an API (GET /things/random) (there is a button to "Get another random thing"), the latter: displays all things: (GET /things).
The problem is that EVERY TIME when I click on Get another random thing and new thing is displayed and I go to recipes route this newly displayed random thing is added to the collection...
Action to get random thing performs a find("random") as suggested in related question and sets this.content to this value.
What is wrong here?
EDIT:
I'm using ember-data and my route is like this:
App.ThingsRoute = Ember.Route.extend({
model: function() {
return App.Thing.find();
}
});
The problem is that EVERY TIME when I click on Get another random thing and new thing is displayed and I go to recipes route this newly displayed random thing is added to the collection...
This is expected behavior. App.Thing.find() does not simply query the api and return results. Instead find() returns an array containing of all Things ember knows about. It includes objects returned by past calls to find(), objects created client-side via App.Thing.createRecord(), and of course individual objects queried via App.Thing.find('random'). After returning this array, find() and kicks off another API call and if that returns additional records they are pushed onto the array.
What is wrong here?
It does not sound like anything is wrong per-se. If you want to prevent random things from showing up in the ThingsRoute, you'll need to change that route's model to be a filter instead of just returning every Thing. For example:
App.ThingsRoute = Ember.Route.extend({
model: function() {
//Kick off query to fetch records from the server (async)
App.Thing.find();
//Return only non-random posts by applying a client-side filter to the posts array
return App.Thing.filter(function(hash) {
if (!hash.get('name').match(/random/)) { return true; }
});
}
});
See this jsbin for a working example
To learn more about filters I recommend reading the ember-data store-model-filter integration test