redux-firestore
redux-firestore copied to clipboard
feat(query): populate document reference or computed child key
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
+1
+1
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.
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.
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
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 That is a great idea! Thanks for sharing
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),
})
)
)