Relationship data and foreign keys?
Opened this issue · 12 comments
Is there any way I could include data from other tables when I only have the ID?
Example of what I'm expecting to achieve:
import { Reference } from "./types"
// Records should be added here to be indexed / made searchable
const references: Array<Reference> = [
{
collection: "comments",
index: "comments",
include: ["text", "user_id"],
},
]
export default references
Instead of indexing user_id
I would like it to get the actual user document based on the ID from users collection.
Is this possible?
Hey @butaminas - I haven't tried it myself, but you should be able to do this via the transform
property.
Something like:
{
// ...
transform: async (data, parent) => {
var user = await parent.ref.firestore.collection("users").doc(data.user_id).get()
if (user.exists) {
return { ...data, ...user.data() }
} else {
return { ...data }
}
}
// ...
}
Be aware that this will require a db lookup for every comment that's inserted.
Anyway, that should work? At least, it should give you an idea of where to go with it.
@acupofjose this does make sense and I think it should work.
However, parent
is undefined in my case. Not really sure why, just started with this library.
Ah whoops, parent
will only be set from a subcollection query. You'll have to import firestore.
Something like:
import firebase from "firebase/app"
import "firebase/firestore"
{
// ...
transform: async (data, parent) => {
var user = await firestore.collection("users").doc(data.user_id).get()
if (user.exists) {
return { ...data, ...user.data() }
} else {
return { ...data }
}
}
// ...
}
@acupofjose This almost works. Only had to import firebase-admin
like this import * as admin from "firebase-admin"
and then access firestore like this admin.firestore()
.
However, whenever I try to run transform
with async I always get empty hits no matter what.
Even if I use transform like this:
transform: async (data, parent) => {
return { ...data }
}
Ah, one more modification then! You'll have to await
the calls in FirestoreHandler.ts
So anywhere there is:
body = this.reference.transform.call(/*...*/)
it should be changed to:
body = await this.reference.transform.call(/* .... */)
I think that oughtta do it
@acupofjose that was exactly it! Thanks!
@acupofjose I just realized that my index won't be updated whenever user data is updated since I include user data via transform.
Is there any way I could link this data together so that the index would stay in sync even when the data from linked collection is updated?
Yeah just add another item into references
for your user collection, make sure it points to your existing index, and be sure that you transform the data to match the structure in elasticsearch
@acupofjose how do I point the user_id
field of comments
index to users
index?
@butaminas I don't know what you're asking - could you clarify? Thanks!
@acupofjose I understand now how to transform the data when it is being indexed.
What I don't fully understand is how do I do the linking so that transformed data would be updated whenever users table is updated.
From your previous comment I understand that this is how I should link users
to comments
:
{
collection: "comments",
index: "comments",
include: ["text", "user_id"],
transform: async (data, parent) => {
// Transformation from Firestore happens here
}
}
{
collection: "users",
index: "comments",
include: ["name"]
}
But it is not linking to the transformed data in comments
index.
What I would like to happen is when the users
collection is updated so that the data in comments
-> user_id
index would also be updated.
Sorry for the delay on this!
It seems like a better idea would be to use the onItemUpserted
property in references and the add an update_by_query from elasticsearch. (You'll have to pull the latest commit on the repo to have access to that)
Something resembling (I'm not sure what your actual structure is):
{
collection: "comments",
index: "comments",
include: ["text", "user_id"],
transform: async (data, parent) => {
// Transformation from Firestore happens here
},
onItemUpserted: async (data, parent, esClient) => {
await esClient.updateByQuery({
index: 'comments',
refresh: true,
body: {
script: {
lang: 'painless',
source: 'ctx._source["user_name"] = data.user.name
},
query: {
match: {
user_id: data.user_id
}
}
}
})
}
}