Is it possible to have ordered data that has been populated?
@benoj No, populatedDataToJS does not currently handle ordered data in v1 (but is a planned feature of populate in v2). You can however do the population from redux by hand since the data is available.
That means that data needed for populating can be gathered with populates in your query config, but you will need to do the mapping yourself.
Something like this if using v1.*.*:
const populates = [{ child: 'owner', root: 'users' }]
@firebaseConnect([
{ path: 'todos', populates}
])
@connect(
(state => ({
todos: dataToJS(state.firebase, 'todos'),
populatedTodos: state.firebase.getIn(['data', 'todos'])
? state.firebase
.getIn(['data', 'todos'])
.map(todo => ({
...todo.toJS(),
// get owner from users in redux defaulting to id if user not found
owner: dataToJS(firebase, `users/${todo.get('owner')}`, todo.owner)
}))
.toJS()
: [],
})
)
Or like this with v2.*.*:
const populates = [{ child: 'owner', root: 'users' }]
@firebaseConnect([
{ path: 'todos', populates }
])
@connect(
(({ firebase: { ordered: { todos }, data: { users } }) => ({
todos,
populatedTodos: todos
? todos.map(todo => ({ ...todo, owner: users[todo.owner] || todo.owner }))
: [],
})
)
Obviously this is not as clean as directly using populatedDataToJS in v1.*.* or populate in v2.*.*, but as mentioned, it will be coming.
Always open to pull requests if you end up looking into the source.
Thanks, will look to migrate to v 2.0.0
Just a further general question w.r.t ordered data. My data looks as below
comments:
-KrcAcNlMnoEIGK7vYy5
author: "30bp2ABAAwXtXR9zovUNTnz3uS62"
text: "bing"
timestamp: 1502842062097
-KreuqJMGaXxIKZiwJUz
author: "30bp2ABAAwXtXR9zovUNTnz3uS62"
text: "bong"
timestamp: 1502884879319
And my query looks like
const populates = [
{ child: 'author', root: `users` }
]
@firebaseConnect((props) => {
const {currentOrg, candidateId} = props
return [
{ path: `/comments`, populates, queryParams: ['orderByChild=timestamp']}
]
})
The comments are coming back as an object, is there a better way to query this so that they are coming back as an ordered list?
The query is no different, you just get it from a different place in redux (i.e. ordered instead of `data). If you are currently using v1, then the following should work:
@connect(
(({ firebase }) => ({
todos: dataToJS(firebase, 'todos'),
orderedTodos: orderedToJS(firebase, 'todos')
})
)
I meant more along the lines of my render method looks like this:
```
Object.keys(comments).map( (commentId) => {
const { text, timestamp, author: { displayName, avatarUrl}} = comments[commentId]
// render comment
})
````
But my understanding is that Object.keys does not necessarily guarantee the order.. is there a better solution to this using the orderedToJS?
@benoj orderedToJS is the same as dataToJS except for the fact that it does guarantee the order since it is an array, so not sure what is meant by "better".
Is there a reason you can't just pass the ordered data as your prop (as indicated in my last example)? That way, when you are mapping you can just to this.props.comments.map(someMapFunc) since ordered data is an Array instead of using Object.keys as needed when mapping.
As mentioned, a way to populate ordered data in v1
I am not seeing an array come through..
With the following I am seeing the ordered never coming through.. Am i misunderstanding how to use it? (Still on v1.5)
const populates = [
{ child: 'author', root: `users` }
]
@firebaseConnect(() => {
return [
{ path: `/comments`, populates, queryParams: ['orderByChild=timestamp']}
]
})
@connect(({ firebase }) => {
const comments = dataToJS(firebase, `/comments`)
const ordered = orderedToJS(firebase,`/comments`)
return {
comments: isLoaded(comments) ? comments || {} : {},
ordered: isLoaded(ordered) ? ordered || [] : [],
}
})
^ here the comments is an object and ordered is coming through as the default []
Hi there,
I'm having some issues to get objects of authenticated user. For the moment, I have to hardcode the Firebase user ID in the "equalTo" query parameter. I think I miss something here but I'm close :) . I'm on the 2.0.0-beta6 by the way.
const populates = [ { orderByChild: 'createdAt' } ]
@UserIsAuthenticated
@firebaseConnect(() => [{
path: '/todos',
populates,
queryParams: [
'orderByChild=owner',
'equalTo=MYFIREBASEUSERID'
]
}
])
@connect(({ firebase: { auth, data: { todos } } }, { params }) => ({
auth,
todos
}))
@neospirit What you are asking about seems to be unrelated to this issue. Feel free to reach out over gitter or open a new issue if you believe you are experiencing a bug.
@benoj Usually I use isLoaded within the component's render itself so I can do different stuff (i.e. show a loader) when data is loading. From the looks of it though, what you are doing should work. Have you checked redux-devtools so you can see how the state looks?
Initial support for populating ordered data has been added to the v2.0.0-beta.8 branch. Unit tests still need to be added.
It can be tested locally before the release with npm linking.
All it takes is placing ordered/ on the front of your populate call like so:
connect(({ firebase }) => ({
todos: populate(firebase, 'todos', populates),
orderedTodos: populate(firebase, 'ordered/todos', populates)
})
This update also comes with a ton of simplification to the populate logic so expanding it in the future should be even easier now.
Initial swing released in v2.0.0-beta.8. It should also work for once queries now too.
Reach out if things don't work as expected.
I've been testing the new populate method (v2.0.0-beta.8), but I think there is an issue with ordered data.
orderedTodos: populate(firebase, 'ordered/todos', populates)
seems to return a (unpopulated) object - I would expect an array.
I've prepared a few failing unit tests, but I want to make sure I understand the expected behaviour before I start debugging the new populate method.
Let me know if I'm missing something - and thank you for a great library.
Hi all, @prescottprue, I am trying to populate ordered data with beta.14, but I can't figure it out. In the code below the state contains firebase.ordered.approvals without the user being populated.
export const Pending: React.SFC<IPendingProps> = ({ data }) => {
if (!data) return null;
console.log('data', data);
return <div>Pending approvals count: {data.length}</div>;
};
const populates = [{ child: 'user', root: 'users' }];
const fbWrapped = firebaseConnect([
{
path: 'approvals',
queryParams: ['orderByChild=status', 'equalTo=pending'],
populates,
},
])(Pending);
export default connect(({ firebase }) => ({
data: populate(firebase, 'ordered/approvals', populates, null),
// data: populate(firebase, 'approvals', populates, null),
}))(fbWrapped);
The commented out version in connect works. So non-ordered data populates as expected. Am I missing something here?
@0x80 The example you provided should be working. Reopened this to track looking into it.
I had a closer look the populate function with a debugger, and I think I spotted the problem.
When using a path in ordered, the value of data will be an array instead of an object. Therefor the last line below results in false, because lodash has() is not made for querying arrays.
// Gather data from top level if path is profile (handles populating profile)
const data = get(state, dotPath, notSetValue)
//.....
// check for if data is single object or a list of objects
const populatesForData = getPopulateObjs(
isFunction(populates)
? populates(last(pathArr), data)
: populates
)
// check each populate child parameter for existence
const dataHasPopluateChilds = every(populatesForData, p => has(data, p.child))
@0x80 Great find! Totally open to a PR if you get the time, if not I will try to get to it when I can. Been switching my company over to v2 recently, so I have been super busy.
BTW why is there a 2.0 branch and a 2.0 beta branch?
If 2.0 is still in beta I'd expect that to be the "next" branch or something, and the beta releases being tags in that branch. Creating this PR I wasn't sure if I should base it on beta.15 or 2.0.0.
There are the two branches since active changes are going onto beta.15, then merged back into v2.0.0. Things were done this way since before there was more than just v1.*.* and v2.*.* (when v1.4.* and v1.5.* were both active).
Totally agree this is unclear though. I like the idea of have the branch matching the tag name, so going to look into doing that. Thanks for the suggestion.
v2.0.0-beta.15 includes a fix for this.
Thanks for the pull request @0x80!
@prescottprue BTW I'm now in the process of moving to Firestore. I read somewhere that populate doesn't work for Firestore yet. Is that correct? Would it require a similar approach?
@0x80 That is the case. populate itself should work the same accept for needing to get passed state.firestore instead of state.firebase. As for they query side of things, firestoreConnect does not support the populates parameter on its query config (the way firebaseConnect does), so that will need to be completed.
Hoping to make some progress on it this weekend.
Most helpful comment
Initial support for populating ordered data has been added to the
v2.0.0-beta.8branch. Unit tests still need to be added.It can be tested locally before the release with npm linking.
All it takes is placing
ordered/on the front of your populate call like so:This update also comes with a ton of simplification to the populate logic so expanding it in the future should be even easier now.