Consulta relación recursiva [RAILS POSTGRES]

492 views
Skip to first unread message

Emanuel Friedrich

unread,
Nov 14, 2016, 10:20:07 AM11/14/16
to rub...@googlegroups.com, rubyco...@googlegroups.com
Hola, tengo un modelo.

Category(id:integer, padre_id:integer,nombre....) conde padre_id es el id de la category de arriba

Tienen idea de , dado un id=1, como puedo obtener los ids de todas las categories que están debajo de la category.id=1?

Por ahora solo se me ocurre traer a memeria la categoria.id=1 y sacar todas sus descendientes, y luego hacer un where in (ids_hijas) pero obviamente deben haber mejores caminos...

una función en la base de datos?

Saludis

--
Emanuel Friedrich 

Cel: 3754-442896

Mariano Ayesa

unread,
Nov 14, 2016, 10:29:13 AM11/14/16
to rub...@googlegroups.com, rubyco...@googlegroups.com
Buenas,

No termino de entender bien esta pregunta en particular Emanuel, pero si luego vas a tener que seguir haciendo mas cosas de ese estilo quizas te convenga mirar https://www.ruby-toolbox.com/categories/Active_Record_Nesting

Saludos,

--
Has recibido este mensaje porque estás suscrito al grupo "rubysur" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a rubysur+unsubscribe@googlegroups.com.
Para acceder a más opciones, visita https://groups.google.com/d/optout.

Emanuel Friedrich

unread,
Nov 14, 2016, 10:32:37 AM11/14/16
to rub...@googlegroups.com
ejemplo concreto:

indumentaria(id=1)>calzados(id=2)>para la mujer(id=3)>botas(4)

llega una request del tipo "dame todos los comercios cuyas categorias sean cualquiera que esté debajo de indumentaria, incluyendo indumentaria"

O sea, debo devolver los comercios cuya catogory_id sea (1,2,3,4)

Ok, gracias, veo


alfredo scoppa

unread,
Nov 14, 2016, 10:47:45 AM11/14/16
to rub...@googlegroups.com

Ricardo

unread,
Nov 14, 2016, 10:47:58 AM11/14/16
to rub...@googlegroups.com
Hola Emanuel,

En mi caso lo resolvi usando una vista, te paso el DDL (funciona para postgres):

CREATE OR REPLACE VIEW categories_vw AS
WITH RECURSIVE tree AS (
   SELECT categories.id, categories.title, categories.parent_id, 1 AS level, ARRAY[categories.id] AS ids
     FROM categories
    WHERE categories.parent_id IS NULL
  UNION ALL
   SELECT c.id, ((rpad(' '::text, p.level * 2) || c.title::text))::character varying(255) AS "varchar", c.parent_id, p.level + 1, p.ids || c.id,
     FROM categories c
     JOIN tree p ON c.parent_id = p.id)
 SELECT tree.id, tree.title, tree.parent_id, tree.level, tree.ids
   FROM tree 
ORDER BY tree.ids;

Luego es cuestion de hacer una consulta del tipo:  SELECT * FROM categories_vw WHERE ids = ARRAY[1,2,3,4];
O podes armarte un modelo que la tabla sea esta vista para poder usarlo desde AR:

Class Category::View
  self.table_name = 'categories_vw'
end

saludos!

Joaquín Vicente

unread,
Nov 14, 2016, 11:47:09 AM11/14/16
to rub...@googlegroups.com
Hay una solución muy simple, pero que a mucha gente le causa pánico de solo pensarlo: Desnormalizar las tablas!
Podés tener una tabla donde haya un registro por cada relación A pertenece a B, ej:

parent               | child
---------------------|----------------------
indumentaria(id: 1)  | calzados(id: 2)
indumentaria(id: 1)  | para la mujer(id: 3)
indumentaria(id: 1)  | botas(id: 4)
calzados(id: 2)      | para la mujer(id: 3)
calzados(id: 2)      | botas(id: 4)
para la mujer(id: 3) | botas(id: 4)

en ese caso, si buscás todos los descendientes de "indumentaria" (parent = 1) te va a devolver:
calzados(id: 2)
para la mujer(id: 3)
botas(id: 4)

y si buscás todos los ancestros de "botas" (child = 4), te va a devolver
indumentaria(id: 1)
calzados(id: 2)
para la mujer(id: 3)

El orden de esta query es O(N), siendo N seguramente un valor muy chico. Y si le ponés índices, vuela! O(log(N)) 
El lado negativo es que te tenés que tomar un poquito más de trabajo al momento de dar de alta las categorías, pero vamos... es super simple y lo hacés solo una vez. Después la query es super simple y te olvidás totalmente de los problemas de queries anidadas!

Emanuel Friedrich

unread,
Nov 21, 2016, 9:41:53 AM11/21/16
to rub...@googlegroups.com
Gracias a todos por sus respuestas. Probablemente vaya a la opción de alfredo. Pero les comento como me va

El 14 de noviembre de 2016, 11:46, Joaquín Vicente <joa...@gmail.com> escribió:
Hay una solución muy simple, pero que a mucha gente le causa pánico de solo pensarlo: Desnormalizar las tablas!
Podés tener una tabla donde haya un registro por cada relación A pertenece a B, ej:

parent               | child
---------------------|----------------------
indumentaria(id: 1)  | calzados(id: 2)
indumentaria(id: 1)  | para la mujer(id: 3)
indumentaria(id: 1)  | botas(id: 4)
calzados(id: 2)      | para la mujer(id: 3)
calzados(id: 2)      | botas(id: 4)
para la mujer(id: 3) | botas(id: 4)

en ese caso, si buscás todos los descendientes de "indumentaria" (parent = 1) te va a devolver:
calzados(id: 2)
para la mujer(id: 3)
botas(id: 4)

y si buscás todos los ancestros de "botas" (child = 4), te va a devolver
indumentaria(id: 1)
calzados(id: 2)
para la mujer(id: 3)

El orden de esta query es O(N), siendo N seguramente un valor muy chico. Y si le ponés índices, vuela! O(log(N)) 
El lado negativo es que te tenés que tomar un poquito más de trabajo al momento de dar de alta las categorías, pero vamos... es super simple y lo hacés solo una vez. Después la query es super simple y te olvidás totalmente de los problemas de queries anidadas!

Reply all
Reply to author
Forward
0 new messages