redux-firestore icon indicating copy to clipboard operation
redux-firestore copied to clipboard

feat(query): populate document reference or computed child key

Open amitava82 opened this issue 6 years ago • 8 comments

What is the feature? My document looks like this

# /version/1/cookList/1
{
"name": "Foo",
 "cook": "/version/1/cook/FJp534F4DegCxOW9y2Os"
}

I want to populate cook whose value is full document path and not just ID. I tried something like this after going though few other issues but it did not work.

const populates = (dataKey, originalData) => {
  if (originalData && originalData['cook'] && !originalData['cookData']) {
    originalData['cookData'] = originalData.cook.split('/')[4];
  }
  return [{child: 'ownerData', root: 'version/1/cook'}]
};

const enhance = compose(
  firestoreConnect([
    { collection: '/version/1/cookList', storeAs: 'cooklist', populates }
  ]),
  connect(({ firestore }) => ({
    cooklist: populate(firestore, 'cooklist', populates)
  }))
);

What version would this apply to? latest

amitava82 avatar Mar 28 '19 05:03 amitava82

+1

CTres avatar Apr 11 '19 12:04 CTres

+1

sultan2Dilawar avatar Apr 11 '19 12:04 sultan2Dilawar

Support for references should hopefully make this possible as well. At first glance, I would hope that the example you provided would work. I'll try to replicate when I get the chance, but thanks for reporting. As always, open to a PR if anyone gets a chance.

prescottprue avatar Apr 18 '19 06:04 prescottprue

Any updates? I'm struggling with whether to use references (not sure how to get them to work with RRF) at all, or go with RRF's populate.

devth avatar Mar 27 '20 02:03 devth

References are not normal objects, so it is an anti-pattern to store them in redux state. Not sure how we will go about supporting this

prescottprue avatar Mar 28 '20 07:03 prescottprue

What if there was something like middleware where if it sees a reference type it either auto resolves the reference to an object or else maybe turns it into a string ID that the user could then optionally populate?

devth avatar Mar 28 '20 15:03 devth

@devth That is a great idea! Thanks for sharing

prescottprue avatar Mar 28 '20 15:03 prescottprue

Thinking about this a little more. populate is great, but one issue I noticed is that there is not a pointer from the string ID stored in the db and the actual collection it belongs to - it relies on the combination of data and code to resolve.

"todos": {
  "ASDF123": {
    "text": "Some Todo Item",
    "owner": "Iq5b0qK2NtgggT6U3bU6iZRGyma2"
   }
 },
 "displayNames": {
   "Iq5b0qK2NtgggT6U3bU6iZRGyma2": "Morty Smith",
   "6Ra53mf3U9Qmdwah6rXBMgY8smu1": "Rick Sanchez"
 },
 "users": {
   "Iq5b0qK2NtgggT6U3bU6iZRGyma2": {
     "displayName": "Morty Smith",
     "email": "[email protected]"
   },
   "6Ra53mf3U9Qmdwah6rXBMgY8smu1": {
     "displayName": "Rick Sanchez",
     "email": "[email protected]"
   }
 }

In other words, if you're just looking at the database, you don't know how to resolve "owner": "Iq5b0qK2NtgggT6U3bU6iZRGyma2". (Of course in this tiny example you could manually match it up to corresponding entities under displayNames and users but in the real world with tons of data this is unrealistic and error prone).

On the plus side, it's interesting and more flexible because populate could join it to displayNames['Iq5b0qK2NtgggT6U3bU6iZRGyma2'] or users['Iq5b0qK2NtgggT6U3bU6iZRGyma2'] depending on what the consumer needs. This is a cool idea but I think it's not worth the cost of bare IDs laying around our DB that we don't know how to resolve unless paired with our ever-evolving and probably-bug-ridden code bases 😅 . Plus, what if you write a separate app without RRF that needs to access the db?

Maybe this is a good reason to constrain it to using refs or some equivalent, like:

"todos": {
  "ASDF123": {
    "text": "Some Todo Item",
    "owner": {
      "id": "Iq5b0qK2NtgggT6U3bU6iZRGyma2",
      "root": "displayNames"
    }
   }
 },

and

const populates = [
  { child: 'owner' }
]
const enhance = compose(
  firebaseConnect([
    { path: '/todos', populates }
    // '/todos#populate=owner:displayNames', // equivalent string notation
  ]),
  connect(
    ({ firebase }) => ({
      todos: populate(firebase, 'todos', populates),
    })
  )
)

devth avatar Apr 02 '20 14:04 devth