title: How can I join data with React native and a many to many firebase firestore collection relationship?
body: <p>I am new to react native and firebase but understand SQL relationships. I am trying to understand how to model many to many relationships with firebase in NoSQL.</p>
  
  <p>In my scenario, users can own multiple groups and groups can have multiple user owners.</p>
  
  <p>I want to display group information (name, city state) for a particular user. (In this case, doc id: WQQZ6pcMMgQoTxH9cr2XGaPOq9W2).</p>
  
  <p>This is how data is structured in the firebase filestore:</p>
  
  <pre><code>{
      "__collections__": {
          "Group": {
              "group3": {
                  "city": "Aurora",
                  "state": "CO",
                  "name": "Group Three",
                  "__collections__": {}
              },
              "group4": {
                  "state": "CO",
                  "name": "Group Four",
                  "city": "Denver",
                  "__collections__": {}
              },
              "group5": {
                  "city": "Aurora",
                  "state": "CO",
                  "name": "Group Five",
                  "__collections__": {}
              }
          },
          "User": {
              "Hm56Zhn9TJP9jVYrzJRqHAB8T8H3": {
                  "last_name": "Sneed",
                  "first_name": "Sam",
                  "__collections__": {}
              },
              "WQQZ6pcMMgQoTxH9cr2XGaPOq9W2": {
                  "last_name": "Smith",
                  "first_name": "Will",
                  "__collections__": {}
              }
          },
          "UserGroups": {
              "F4GubhZKqWcJnHahL0TQTOP62Jj1": {
                  "group3": true,
                  "group4": true,
                  "__collections__": {}
              },
              "WQQZ6pcMMgQoTxH9cr2XGaPOq9W2": {
                  "group5": true
                  "__collections__": {}
              }
          }
      }
  }
  </code></pre>
  
  <p>Here is my code:</p>
  
  <pre><code>export default class GroupSelect extends Component {
      constructor(props) {
  
          super(props);
  
          this.userGroupRef = firebase.firestore().collection("UserGroups").doc('WQQZ6pcMMgQoTxH9cr2XGaPOq9W2');
  
          this.state = {
              userGroups: [
                  {
                      uid: 'group1',
                      name: 'Group One',
                      city: 'Chicago',
                      state: 'IL'
                  },
                  {
                      uid: 'group2',
                      name: 'Group Two',
                      city: 'Denver',
                      state: 'CO'
                  }
              ]
          }
      }
  
      componentDidMount() {
  
          this.userGroupRef.get().then((doc) =&gt; {
  
              var obj = doc._data;
  
              var group_ids = Object.keys(obj).map(function (key) {
                  return key;
              });
  
              var groups = [];
  
              var group = {};
  
              group_ids.forEach(function (group_id) {
  
                  console.log(group_id);
  
                  this.groupRef = firebase.firestore().collection('Group').doc(group_id);
                  this.groupRef.get().then((groupDoc) =&gt; {
                      group.name = groupDoc._data['name'];
                      group.city = groupDoc._data['city'];
                      group.state = groupDoc._data['state'];
                      groups.push(group);
                  });
  
              });
  
              console.log(groups); //not populated correctly
  
              // this.setState({
              //     userGroups: groups
              // });
          });
      }
  
      render() {
          return (
              this.state.userGroups.map((userGroup, index) =&gt; (
                  &lt;Text&gt;{userGroup.name} - {userGroup.city}, {userGroup.state}&lt;/Text&gt;
              ))
          )
      }
  }
  </code></pre>
  
  <p>If I comment out everything in ComponentDidMount(), the render() shows the original contents of state.UserGroups correctly. But, when I try to populate the array in the ComponentDidMount() and reset the state userGroups var, there is a problem with the join and the timing of the population of the array.</p>
  
  <p>How best to do this?</p>
  
  <p>I am patterning this off of how firebase joins are described here:
  <a href="https://www.youtube.com/watch?v=Idu9EJPSxiY" rel="nofollow noreferrer">https://www.youtube.com/watch?v=Idu9EJPSxiY</a></p>
  
  <p><img src="https://i.stack.imgur.com/B9BFE.png" alt="Users, eventAttendees and Events many-to-many join in firebase realtime db"><br>
  <sup>Users, eventAttendees and Events many-to-many join in firebase realtime db</sup></p>
  
  <p>But, this uses the realtime database instead of filestore, which is what I want to use.</p>
  
  <p>I want to do the same but with: Users, UserGroups, and Groups</p>
  
  <p>Should the data be structured differently?</p>
  
  <hr>
  
  <p><strong>I implemented Frank van Puffelen's answer below.</strong> 
  <strong>It works but that brings up other questions.</strong></p>
  
  <p>If I use the UserGroups collection as described...</p>
  
  <pre><code>constructor(props) {
  
      super(props);
  
      this.userGroupRef = firebase.firestore().collection("UserGroups").doc(firebase.auth().currentUser.uid);
  
      this.state = {
          userGroups: []
      }
  }
  </code></pre>
  
  <p>...it works, but see possible "issues" below.</p>
  
  <pre><code>componentDidMount() {
  
      this.userGroupRef.get().then((doc) =&gt; {
  
          var obj = doc._data;
  
          //get array of group ids
          var group_ids = Object.keys(obj).map(function (key) {
              return key;
          });
  
          let promises = [];
  
          //issue: making singleton database calls for each group id, maybe not good.
          group_ids.forEach(function (group_id) { 
              promises.push(firebase.firestore().collection('Group').doc(group_id).get())
          });
  
          let groups = [];
  
          let parentThis = this; //issue: get ref to parent this to set in Promise.all below, kinda weird, maybe not so clear
  
          Promise.all(promises).then(function(docs) {
  
              docs.forEach((groupDoc) =&gt; {
                  let group = {};
                  group.name = groupDoc._data['name'];
                  group.city = groupDoc._data['city'];
                  group.state = groupDoc._data['state'];
                  groups.push(group);
              });
  
              parentThis.setState({
                  userGroups: groups
              });
          });
      });
  }
  </code></pre>
  
  <p>If I restructure data and add a groups collection below User...</p>
  
  <pre><code>"User": {
      "WQQZ6pcMMgQoTxH9cr2XGaPOq9W2": {
          "last_name": "Carter",
          "first_name": "Will",
          "__collections__": {
              "Groups": {
                  "group1": {
                      "city": "Chicago",
                      "state": "IL",
                      "name": "Group One",
                      "__collections__": {}
                  },
                  "group2": {
                      "city": "Denver",
                      "state": "CO",
                      "name": "Group Two",
                      "__collections__": {}
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>Then, code becomes more straightforward.</p>
  
  <pre><code>constructor(props) {
  
      super(props);
  
      //path: User/WQQZ6pcMMgQoTxH9cr2XGaPOq9W2/Groups 
      this.userGroupRef = firebase.firestore().collection("User").doc(firebase.auth().currentUser.uid).collection("Groups");
  
      this.state = {
          userGroups: []
      }
  }
  
  componentDidMount() {
  
      this.userGroupRef.get().then((doc) =&gt; {
  
          let groups = [];
  
          doc._docs.forEach(function (groupDoc) {
              let group = {};
              group.name = groupDoc._data['name'];
              group.city = groupDoc._data['city'];
              group.state = groupDoc._data['state'];
              groups.push(group);
          });
  
          this.setState({
              userGroups: groups
          });
  
      });
  
  }
  </code></pre>
  
  <p>This method seems cleaner to me. But now I have duplicate data in a root Group collection and under User collection.</p>
  
  <p>Is it better to do it in this method with duplicate Group data in the db?</p>
  
  <p>I have a relational db background and learning NoSQL best practices. My instinct is not to duplicate data in the db.</p>