Cuando uno empieza con Supabase, la forma en que maneja los JOIN te puede parecer magia o, derechamente, una caja negra. Y la verdad es que es un poco de ambas, y eso no siempre es bueno. A mí, personalmente, esta abstracción me genera un poco de ruido porque me gusta saber qué está pasando por debajo.
La pregunta es súper válida: ¿cómo sabe Supabase qué columnas juntar si no le decimos explícitamente? Bueno, la clave está en las llaves foráneas (Foreign Keys). Supabase asume que si dos tablas tienen una relación definida por una FK, esa es la que quieres usar para hacer el join.
El caso simple: una relación, una tabla
Si tenés una tabla countries y otra cities, y cities tiene una FK que apunta a countries (o viceversa, depende de cómo lo modeles, pero el ejemplo de SO lo hace así), Supabase es bastante inteligente. Con esto, ya sabe qué hacer:
const { data, error } = await Supabase
.from('countries')
.select(`
name,
cities (
name
)
`)
Aquí, cities está implícitamente unida a countries a través de la llave foránea que exista entre ellas. Supabase deduce la relación y trae los datos relacionados. Funciona y es súper cómodo para casos sencillos. No hay que especificar ON ni nada de eso, lo cual es rápido para prototipar.
Cuando la cosa se complica: múltiples relaciones o aliasing
El problema surge cuando una tabla tiene múltiples relaciones con otra, o incluso consigo misma. Imaginate una tabla products que tiene un supplier_id y un purchaser_id, y ambos son llaves foráneas que apuntan a una tabla companies (o users, lo que sea). Ahí la magia de la inferencia se topa con un muro.
Supabase no puede adivinar cuál de las dos FK quieres usar si solo pones select('companies (*)'). Para eso, tenés que ser explícito usando un alias. Es la forma de decirle a Supabase: “Ojo, quiero unir esta columna específica de mi tabla principal con la tabla relacionada, y quiero que la llames de esta forma en el resultado”.
const { data, error } = await supabase
.from('products')
.select(`
id,
supplier:supplier_id ( name ),
purchaser:purchaser_id ( name )
`)
Aquí, supplier:supplier_id le indica a Supabase que el alias para esta relación será supplier y que la llave foránea que debe usar es la que está en la columna supplier_id de la tabla products. Lo mismo para purchaser:purchaser_id. Simple, funcional, y te da el control que necesitas.
Esto me gusta mucho más, de hecho. Prefiero un poco más de verbosidad si eso me da claridad sobre lo que está pasando, en vez de tener que ir a revisar el esquema de la base de datos cada vez que veo un join implícito.
Lo que aprendí tarde
Lo que me costó entender al principio con herramientas como Supabase, y ojalá lo hubiera sabido antes, es que por muy potente que sea la abstracción que te ofrecen, siempre tenés que entender el SQL que corre por debajo y cómo funciona tu base de datos. La magia es genial hasta que algo no funciona como esperabas, y ahí no hay más que ir a revisar los cimientos.