Populate

Populate allows you to replace IDs within your data with other data from Firebase. This is very useful when trying to keep your data flat. Some would call it a join, but it was modeled after the mongo populate method.

Initial data from populate is placed into redux in a normalized pattern following defined redux practice of normalizing. populatedDataToJS helper used in the connect function then builds populated data out of normalized data within redux (NOTE: This does not apply if you are using v1.1.5 or earlier).

A basic implementation can look like so:

const populates = [
  { child: 'owner', root: 'users' } // replace owner with user object
]

@firebaseConnect([
  // passing populates parameter also creates all necessary child queries
  { path: 'todos', populates }
])
@connect(({ firebase }) => ({
  // populate original from data within separate paths redux
  todos: populatedDataToJS(firebase, 'todos', populates),
  // dataToJS(firebase, 'todos') for unpopulated todos
}))

Some Things To Note

  • Population happens in two parts:
    1. firebaseConnect - based on populate settings, queries are created for associated keys to be replaced. Query results are stored in redux under the value of root in the populate settings.
    2. connect - Combine original data at path with all populate data (in redux from queries created by passing populate settings to firebaseConnect)
  • Populate creates a query for each key that is being replaced
  • Results of populate queries are placed under their root

Examples

List of todo items where todo item can contain an owner parameter which is a user's UID like so:

{ "text": "Some Todo Item", "owner": "Iq5b0qK2NtgggT6U3bU6iZRGyma2" }
Example Data
"todos": {
  "ASDF123": {
    "text": "Some Todo Item",
    "owner": "Iq5b0qK2NtgggT6U3bU6iZRGyma2"
   }
 },
 "displayNames": {
   "Iq5b0qK2NtgggT6U3bU6iZRGyma2": "Morty Smith",
   "6Ra53mf3U9Qmdwah6rXBMgY8smu1": "Rick Sanchez"
 }
 "users": {
   "Iq5b0qK2NtgggT6U3bU6iZRGyma2": {
     "displayName": "Morty Smith",
     "email": "mortysmith@gmail.com"
   },
   "6Ra53mf3U9Qmdwah6rXBMgY8smu1": {
     "displayName": "Rick Sanchez",
     "email": "rick@email.com"
   }
 }

String, Number, or Boolean

When trying to replace the owner parameter with a string such as a displayName from a /displayNames root follow the pattern of #populate=paramToPopulate:populateRoot.

Example Query
const populates = [
  { child: 'owner', root: 'displayNames' }
]
@firebaseConnect([
  { path: '/todos', populates }
  // '/todos#populate=owner:displayNames', // equivalent string notation
])
@connect(
  ({ firebase }) => ({
    todos: populatedDataToJS(firebase, 'todos', populates),
  })
)
Result
ASDF123: {
  text: 'Some Todo Item',
  owner: 'Morty Smith'
 }

Object

Population can also be used to populate a parameter with an object. An example of this would be populating the owner parameter, which is an ID, with the matching key from the users list.

Example Query
const populates = [
  { child: 'owner', root: 'users' }
]
@firebaseConnect([
  { path: '/todos', populates }
  // '/todos#populate=owner:users' // equivalent string notation
])
@connect(
  ({ firebase }) => ({
    todos: populatedDataToJS(firebase, 'todos', populates),
  })
)
Example Result
ASDF123: {
  text: 'Some Todo Item',
  owner: {
    displayName: 'Morty Smith',
    email: 'mortysmith@gmail.com'
  }
}
Keep Object's Key

Often when populating, you will want to keep the key that was originally there (before being replaced by populated value). This is supported through the use of keyProp:

Example Query
const populates = [
  { child: 'owner', root: 'users', keyProp: 'key' }
]
@firebaseConnect([
  { path: '/todos', populates }
  // '/todos#populate=owner:users' // equivalent string notation
])
@connect(
  ({ firebase }) => ({
    todos: populatedDataToJS(firebase, 'todos', populates),
  })
)
Example Result
ASDF123: {
  text: 'Some Todo Item',
  owner: {
    key: 'Iq5b0qK2NtgggT6U3bU6iZRGyma2',
    displayName: 'Scott Prue',
    email: 'scott@prue.io'
  }
}

Object's Parameter

There is also the option to load a parameter from within a population object. An example of this could be populating the owner parameter with the email property of the user with a matching ID:

Example
const populates = [
  { child: 'owner', root: 'users', childParam: 'email' }
]
@firebaseConnect([
 { path: '/todos', populates }
 // '/todos#populate=owner:users:email' // equivalent string notation
])
@connect(({ firebase }) => ({
  todos: populatedDataToJS(firebase, 'todos', populates),
}))
Example Result
ASDF123: {
  text: 'Some Todo Item',
  owner: 'mortysmith@gmail.com'
}

Profile Parameters

To Populate parameters within profile/user object, include the profileParamsToPopulate parameter when calling reactReduxFirebase in your compose function.

Parameter

Example Config

Populating username with username from usernames ref.

const config = {
  userProfile: 'users',
  profileParamsToPopulate: [
    'displayName:displayNames',
    // { child: 'displayName', root: 'displayNames' } // object notation
  ]
}
Initial Data
{
  users: {
    $uid: {
      email: 'test@test.com',
      displayName: 'Iq5b0qK2NtgggT6U3bU6iZRGyma2'
    }
  }
}
Example Result
{
  users: {
    $uid: {
      email: 'test@test.com',
      displayName: 'someuser'
    }
  }
}

List of Items

Example Config
const config = {
  userProfile: 'users',
  profileParamsToPopulate: [ 'todos:todos' ] // populate list of todos from todos ref
}
Initial Data
{
  users: {
    $uid: {
      email: 'test@test.com',
      todos: {
        0: "ASDF123"
      }
    }
  }
}
Example Result
{
  users: {
    $uid: {
      email: 'test@test.com',
      todos: {
        ASDF123: {
          text: 'Some Todo Item',
          owner: "Iq5b0qK2NtgggT6U3bU6iZRGyma2"
        }
      }
    }
  },
  todos: {
    ASDF123: {
      text: 'Some Todo Item',
      owner: "Iq5b0qK2NtgggT6U3bU6iZRGyma2"
    }
  }
}

results matching ""

    No results matching ""