React-redux-firebase: question(query): query a firestore document based on firebase auth uid

Created on 26 Nov 2017  路  15Comments  路  Source: prescottprue/react-redux-firebase

Is it possible to query a document from firestore based on the auth uid coming from the firebase, within the same composed enhancer?

I'm trying to do something like this:

export default compose(
  firebaseConnect(),
  firestoreConnect(props => [
    { collection: 'registrations', doc: props.auth.uid }, 
  ]),
  connect(({ firebase: { auth }, firestore: {ordered} }) => ({
    auth,
    ordered.registrations && ordered.registrations[??]
  }))
)(Onboarding) as any;

I find the documentation about Firestore highly confusing. Every example takes a different approach and some of it is incomplete like the example under Automatic here, where the last todoId is not defined.

question

Most helpful comment

@prescottprue personally, I must do something like this to make it works:

const mapStateToProps = ({ firebase: { auth }, firestore: { ordered } }) => ({
  auth,
  memberships: ordered.memberships,
});

export default compose(
  withStyles(styles),
  connect(mapStateToProps, mapDispatchToProps), // Before firestoreConnect
  firestoreConnect(props => [
    {
      collection: 'members',
      storeAs: 'memberships',
      where: [['user.uid', '==', props.auth.uid]],
    },
  ])
)(Home);

All 15 comments

Also I ran into some example code in the docs where auth was taken from firestore instead of firebase. Is it possible to use firestoreConnect for auth? I don't see it documented anywhere.

Yes, it is possible to use the auth from Firebase to query Firestore (you don't need to add firebaseConnect since firebase state lives in redux. So this should work fine:

export default compose(
  firestoreConnect(props => [
    { collection: 'registrations', doc: props.auth.uid }, 
  ]),
  connect(({ firebase: { auth }, firestore: {ordered} }) => ({
    auth,
    ordered.registrations && ordered.registrations[??]
  }))
)(Onboarding) as any;

There is not currently support for grabbing auth from Firestore state (as it would require redux-firestore having an auth reducer).

I'm going to clean up the examples a bit more since I agree they are unclear and there are definitely typos.

@0x80 Going to close this. Let me know if the usage is still not clear or if you think it should be added somewhere else in the docs.

Thanks for reaching out.

@prescottprue personally, I must do something like this to make it works:

const mapStateToProps = ({ firebase: { auth }, firestore: { ordered } }) => ({
  auth,
  memberships: ordered.memberships,
});

export default compose(
  withStyles(styles),
  connect(mapStateToProps, mapDispatchToProps), // Before firestoreConnect
  firestoreConnect(props => [
    {
      collection: 'members',
      storeAs: 'memberships',
      where: [['user.uid', '==', props.auth.uid]],
    },
  ])
)(Home);

@QuentinBrosse Yup, thats how you pass auth as a prop. Definitely needed to create a query with auth.uid.

Does anything need to be added to the docs to make this more clear?

I don't think so, it was just to complete your previous answer who does not worked in my case. :)

I may have the same question as the OP so I want to ensure this was answered, and if so I'll open a new question. Specifically, I'm questioning what to put in the ?? of the following, (copied from above):

connect(({ firebase: { auth }, firestore: {ordered} }) => ({
  auth,
  ordered.registrations && ordered.registrations[??]
}))

In my case, what would be registrations is an array and not an object. Am I supposed to search the array to find the correct document? It feels a bit redundant to specify both firestoreConnect(['collectionName/itemId']) _and_ the connect piece so I wonder if I'm doing this completely wrong.

Edit: Here is the same point in the documentation. In my case, ordered.todos is an array, not an object.

@cazzer In the case that you are using storeAs (like @QuentinBrosse 's example above) you shouldn't need to get from a specific piece of the the array in connect, it is the whole array that you want. However, if you do not use store as, you are intending to get the specific document - in that case I suggest getting it from data instead of ordered (typo in the original post that will be corrected).

Just to clarify a few things:

  • Using storeAs places the result of your query into specific location of redux (different than its path which is the default when storeAs is not used) - this means it can be used as a way to not need the id within your connect
  • In order for auth to be on props, it needs to be passed as a prop. This can happen by using connect (pictured below) or by connecting a parent component and passing it as a prop.
  • ordered contains array data data contains data by doc id, so if you have the id when making the listener you should should get documents from there or use storeAs

@cazzer if you are getting one item you will likely want:

import { compose }  from 'redux'
import { branch, renderComponent, mapProps } from 'recompose';

compose(
  // Create a listener for a single registration
  firestoreConnect(props => [
    {
      collection: 'registrations',
      doc: 'itemId',
      // storeAs: 'myRegistration', // not nessesary, but can prevent needing id in connect
      where: ['user.uid', '==', props.auth.uid],
    },
  ]),
  connect(({ firestore: { data } }, { itemId }) => ({
    registration: data.registrations[itemId],
    // registration: data.myRegistration, // if using storeAs
  }))
)

Where if you are trying to get a list of items not knowing a single id you would want:

compose(
  // connect auth from redux state to the auth prop
  connect(({ firebase: { auth } }) => ({ auth })),
  // Show spinner while auth is loading
  spinnerWhileLoading(['auth']),
  // Create a listener for registrations where user.uid == current user uid
  firestoreConnect(props => [
    {
      collection: 'registrations',
      where: ['user.uid', '==', props.auth.uid],
    },
  ]),
  connect(({ firestore: { ordered } }) => ({
    registration: ordered.registrations // an array list of registrations
  }))
)

The source for spinnerWhileLoading can be found in the query docs

Thanks for the extensive examples, that clears up my question. I missed the connect(({ firestore: { data }})... piece entirely when I initially browsed the documentation.

Hi, when I try to use firestoreConnect to filter by uid, I get this error "FirebaseError: Function Query.where() requires a valid third argument, but it was undefined."
I am trying to return a collection
where: [[ 'userID', '==', props.auth.uid ]]
So it doesn't seem to recognise props even thought I pass it into firestoreConnect( (props) => ...
Could someone please help?

@vincenzomann You are most likley running the query before auth is defined. You need to wait for data to load, as shown in the query docs and the state based query snippet example. This is also commonly done with HOCs as described in further down in that same page.

Always feel free to reach out over gitter with questions or open an issue if things are not working as you expect.

@prescottprue Thank you! I literally solved it 10 minutes ago but really appreciate it :)

Just chiming in to say, I could only get this to work when I put connect before firestoreConnect in my compose function. Definitely seems weird, and is not what I see in examples above, but maybe it will help someone. Was pulling my hair out on this one.

@sgtpenguin agreed that is the correct way to make it work. That is what is described above and done in state based query snippet example by placing the connect in a component above where the firebaseConnect.

hi @prescottprue, In my component, I am returning a query that meets a certain condition but the first time the components mounts, it returns all the data in the array before returning the queried data after some seconds. How can I solve this?

My firestoreConnect function

export default compose(
connect(mapStateToProps, mapDispatchToProps),
firestoreConnect((props) => {
return [
{
collection: "blogs",

    where: ["authorId", "==", props.auth.uid],
    orderBy: ["createdAt", "desc"],
  },
];

})
)(UserProfile);

Was this page helpful?
0 / 5 - 0 ratings