Relaciones usando MongoDB GORM

Hoy me encontré con un nuevo desafío. Necesitaba hacer una consulta, considerando una tabla relacionada, teniendo configurado el plugin MongoDB GORM. Gran desafío, porque MongoDB no soportan JOINs, entonces, la implementación del plugin directamente las omite (cosa que pareciera ser el comportamiento clásico en este aspecto: si no se que es, en vez de disparar un error, directamente no lo tomo en cuenta).

En líneas generales, me han dado muchísimas satisfacciones los plugins de Grails. Este en particular está mantenido por uno de los desarrolladores principales de toda la arquitectura, así que menos todavía. Aunque en esta ocasión, mi problema era algo parecido a esto. Nota mental: siempre buscar información entre los bugs cuando tenemos un problema.

Resumiendo, lo encontrado fue:

  • Un lindo conjunto de recetas para usar GORM. Ver link.
  • Cuando se quiere obtener información relacionada, a pesar que lo lógico podría ser buscar a través de eq("parent.id", valor), en realidad hay que usar eq("parent") porque es así como lo resguarda en Mongo
    • Cuando se guarda la informacion en la base de datos, a diferencia de cuando usamos Hibernate, el campo no tiene el nombre parent_id ni tampoco se crea un mapa, como para que pueda ser obtenido como parent.id, sencillamente el nombre del campo en la base será equivalente al nombre del atributo en nuestro clase de dominio.
  • Cuando querramos obtener filtros usando tablas relacionadas, una forma es buscar los identificadores en las relacionadas y después, como tenemos una referencia en nuestra tabla, usar esos identificadores.

 

/**
 *  Los Ids son diferentes a los estándard, para mostrar que el ejemplo es versatil
 */
class Parent {
  Long id
  // Aquí puede haber información del tipo
  // miMapa = { id: 1, texto: 'xxyyzz', ...}
  Map miMapa 
  // .. 
  static hasMany = [child: Child]

}

class Child {
  String id
  // ..
  static belongsTo = [parent: Parent]
}

/**
 * Nuestro objetivo es buscar los Childs, 
 * cuyo padre tengan la propiedad parent.miMapa.id = id
 * (esto se resolvería muy fácil con un JOIN de SQL, pero en NoSQL no tenemos esa opción)
 * child.parent.miMapa.id == 1 --> debería estar en los resultados
 * child.parent.miMapa.id != 1 --> **NO** debería estar en los resultados
 */

def id = 123 // id que voy a buscar

def parents = Parent.createCriteria().list {
  eq("miMapa.id", id)
}
def parents_ids = parents.id

def resultados = Child.createCriteria().list {
  inList("parent", parents_ids)
}

resultados.each() { it ->
  assert(it.parent.miMapa.id == id)
}

Si alguien tuvo ese problema, aquí tienen una solución “saludable”. 🙂


Discussion Area - Leave a Comment