Reputation: 641
I'm building an app that in which users can make posts and then vote on them. I want to be able to request the list of posts from firebase and order them by vote count. How can I do this?
My data is structure like this:
I'm attempting to fire this action:
export const fetchPostsByHottest = () => {
return (dispatch) => {
firebase.database().ref('/social/posts')
.orderByChild('vote_count')
.on('value', snapshot => {
dispatch({ type: HOT_POSTS_FETCH_SUCCESS, payload: snapshot.val() });
});
};
};
It just comes back in the normal order, by push key.
I've been told that snapshot.val() converts the snapshot into a regular JS object and kills any order.
This is my reducer:
import {
HOT_POSTS_FETCH_SUCCESS,
} from '../actions/FeedActions/types';
const INITIAL_STATE = {
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case HOT_POSTS_FETCH_SUCCESS:
return action.payload;
default:
return state;
}
};
I then try to map the state to props in my feed
component:
const mapStateToProps = state => {
const posts = _.map(state.hotFeed, (val, uid) => {
return { ...val, uid };
});
return { posts: posts.reverse() };
};
I do it like this as I need to get both the Value AND the UID from each of the post objects.
If I try and do turn it into an array in the action like this:
export const fetchPostsByHottest = () => {
return (dispatch) => {
firebase.database().ref('/social/posts')
.orderByChild('vote_count')
.on('value', snapshot => {
const nodes = [];
snapshot.forEach(child => nodes.push(child.val()));
console.log(nodes);
dispatch({ type: HOT_POSTS_FETCH_SUCCESS, payload: nodes });
});
};
};
Then it will only bring me back one of the posts and it won't give me the UID either.
How can I work around this? :S
Thank you!
Matt
Upvotes: 1
Views: 559
Reputation: 58400
The query in your last snippet should be correct. There is no reason it should return only a single post. However, it's possible that the snapshot's forEach
is being short-circuited:
The callback can return true to cancel further enumeration.
push
returns the new length and it's possible that forEach
is testing for any truthy value - not just true
- and is cancelling further enumeration. Use a block to ensure undefined
is returned.
Also, you can obtain the key using the child's key
property.
firebase.database().ref('/social/posts')
.orderByChild('vote_count')
.once('value', snapshot => {
const nodes = [];
snapshot.forEach(child => { nodes.push({ ...child.val(), key: child.key }); });
console.log(nodes);
dispatch({ type: HOT_POSTS_FETCH_SUCCESS, payload: nodes });
});
Also, for your use case, once
seems more appropriate than on
.
Upvotes: 3