{"id":21946,"date":"2022-10-14T11:35:34","date_gmt":"2022-10-14T09:35:34","guid":{"rendered":"https:\/\/blog.basetis.com\/article_basic\/filtrar-jerarquias-con-java\/"},"modified":"2024-03-12T15:01:12","modified_gmt":"2024-03-12T13:01:12","slug":"filtrar-jerarquias-con-java","status":"publish","type":"article_basic","link":"https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/","title":{"rendered":"Filtrar jerarqu\u00edas con Java"},"content":{"rendered":"<h1>Introducci\u00f3n<\/h1>\n<p>A veces una aplicaci\u00f3n necesita operar sobre datos jer\u00e1rquicos que se encuentran en una BBDD, es decir, tablas que tienen una relaci\u00f3n sobre s\u00ed&nbsp;mismas (del tipo categor\u00eda-subcategor\u00edas). Cuando las operaciones son sencillas no se necesita nada especial, pero en cuanto es necesario filtrar datos por niveles de la jerarqu\u00eda u obtener un nodo concreto del \u00e1rbol, la cosa se complica, ya que los mecanismos que ponen a nuestra disposici\u00f3n tanto Java como&nbsp;la mayor\u00eda de frameworks, son limitados en este aspecto.<\/p>\n<p>Los tipos de soluci\u00f3n que detallo m\u00e1s adelante, est\u00e1n basados en un \u00e1rbol de categor\u00edas, una forma simple de entender e imaginar una jerarqu\u00eda de datos.<\/p>\n<h2>&nbsp;<\/h2>\n<h2>Ejemplo de categor\u00edas<\/h2>\n<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\" style=\"width:50%\">\n<thead>\n<tr>\n<th colspan=\"3\" scope=\"col\">\n<p><span style=\"font-size:16px\"><strong>Tabla Category<\/strong><\/span><\/p>\n<\/th>\n<\/tr>\n<tr>\n<th colspan=\"1\" rowspan=\"1\" scope=\"col\">\n<p class=\"rteleft\"><strong>id<\/strong><\/p>\n<\/th>\n<th colspan=\"1\" rowspan=\"1\" scope=\"col\">\n<p class=\"rteleft\"><strong>parent_id<\/strong><\/p>\n<\/th>\n<th colspan=\"1\" rowspan=\"1\" scope=\"col\">\n<p class=\"rteleft\"><strong>description<\/strong><\/p>\n<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">1<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">null<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item1<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">2<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">1<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item1.1<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">3<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">1<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item1.2<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">4<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">null<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">5<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">4<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2.1<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">6<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">5<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2.1.1<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">7<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">5<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2.1.2<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">8<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">7<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2.1.2.1<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">9<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">7<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2.1.2.2<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">10<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">7<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2.1.2.3<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>Si pensamos en el \u00e1rbol que corresponde con la jerarqu\u00eda de datos de la tabla de categor\u00edas, se traducir\u00eda en esto:<\/p>\n<ul>\n<li>\n<p><strong>Item1<\/strong><\/p>\n<ul>\n<li>\n<p><strong>Item1.1<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>Item1.2<\/strong><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Item2<\/strong><\/p>\n<ul>\n<li>\n<p><strong>Item2.1<\/strong><\/p>\n<ul>\n<li>\n<p><strong>Item2.1.1<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>Item2.1.2<\/strong><\/p>\n<ul>\n<li>\n<p><strong>Item2.1.2.1<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>Item2.1.2.2<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>Item2.1.2.3<\/strong><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h1>&nbsp;<\/h1>\n<h1>Tipos de soluci\u00f3n<\/h1>\n<p>Hay varias formas de afrontar el problema, que depender\u00e1n del framework y arquitectura del proyecto, el tama\u00f1o de los datos, el peso que se otorgue a la optimizaci\u00f3n, etc.<\/p>\n<h2>&nbsp;<\/h2>\n<h2>Query nativa<\/h2>\n<p>La opci\u00f3n menos deseable, pero probablemente la m\u00e1s r\u00e1pida y f\u00e1cil de implementar.<\/p>\n<p>Esta opci\u00f3n trae consigo varias desventajas, que la hacen por lo general la peor opci\u00f3n. Entre sus principales desventajas se encuentran la dif\u00edcil legibilidad de escribir queries en el c\u00f3digo y la dependencia con el motor de BBDD.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Ejemplo con query nativa de Oracle SQL<\/strong><\/p>\n<div>\n<pre>\r\n<span style=\"font-size:12px\"><span style=\"font-family:Courier New,Courier,monospace\">SELECT\r\n    id,\r\n    parent_id,\r\n    level,\r\n    description,\r\nFROM\r\n    category\r\nWHERE\r\n    level &lt;= 3\r\nSTART WITH\r\n    id = 4 <span style=\"color:#d35400\">\/* Nodo inicial del \u00e1rbol *\/<\/span>\r\nCONNECT BY\r\n    PRIOR id = parent_id;<\/span><\/span><\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Se pueden observar las palabras clave \u201clevel\u201d, \u201cstart with\u201d y \u201cconnect by prior\u201d que permiten acceder a la estructura de \u00e1rbol de una tabla con datos jer\u00e1rquicos.<\/p>\n<p>Esta query mostrar\u00eda los siguientes resultados:<\/p>\n<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\" style=\"width:50%\">\n<thead>\n<tr>\n<th colspan=\"1\" rowspan=\"1\" scope=\"col\">\n<p><strong>id<\/strong><\/p>\n<\/th>\n<th colspan=\"1\" rowspan=\"1\" scope=\"col\">\n<p><strong>parent_id<\/strong><\/p>\n<\/th>\n<th colspan=\"1\" rowspan=\"1\" scope=\"col\">\n<p><strong>level<\/strong><\/p>\n<\/th>\n<th colspan=\"1\" rowspan=\"1\" scope=\"col\">\n<p><strong>description<\/strong><\/p>\n<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">4<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">null<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">1<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">5<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">4<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">2<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2.1<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">6<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">5<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">3<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2.1.1<\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">7<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">5<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">3<\/span><\/p>\n<\/td>\n<td colspan=\"1\" rowspan=\"1\">\n<p><span style=\"color:#4e5f70\">Item2.1.2<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<h2>&nbsp;<\/h2>\n<h2>Vista de BBDD<\/h2>\n<p>Esta opci\u00f3n generalmente es mejor que una query nativa \u2014probablemente la mejor opci\u00f3n\u2014, ya que de cara a la aplicaci\u00f3n, nos comunicamos con una vista (que es equivalente a una tabla). La contrapartida, es que requiere el mantenimiento de un nuevo elemento en la BBDD, la nueva vista.<\/p>\n<p>Crear una vista no tiene misterio, siguiendo el ejemplo anterior, podr\u00edamos crearla utilizando la query nativa. La ventaja es que para la aplicaci\u00f3n ser\u00eda transparente c\u00f3mo est\u00e9 creada la vista, la tratar\u00edamos como a una tabla de consulta.<\/p>\n<p>La clave est\u00e1 en que la vista contenga el campo \u00ablevel\u00bb, para poder hacer consultas simples desde Java. Por ejemplo, esto nos permitir\u00eda traernos todo el \u00e1rbol y hacer la consulta con Java Stream API,&nbsp;crear una query JPQL, crear una query con&nbsp;Criteria API,&nbsp;usar los Repository de Spring Framework, etc.<\/p>\n<h1>&nbsp;<\/h1>\n<h2>JPQL\/Creiteria API<\/h2>\n<p>En la teor\u00eda esta ser\u00eda la opci\u00f3n m\u00e1s deseable, ya que es la m\u00e1s flexible y agn\u00f3stica al motor de BBDD, sin embargo existen una serie de limitaciones a la hora de realizar consultas sobre tablas jer\u00e1rquicas que impiden realizar consultas \u00f3ptimas.<\/p>\n<p>El concepto de nivel y nodo no est\u00e1n disponibles en JQPL o Creiteria API y eso provoca que tengamos que traernos casi todo el bloque de datos y realizar un filtrado manual en Java.<\/p>\n<p>Si el volumen de datos es peque\u00f1o y el rendimiento no es un problema, esta ser\u00eda una opci\u00f3n a tener en cuenta.<\/p>\n<h2>&nbsp;<\/h2>\n<h2>EclipseLink + JPQL\/Criteria API<\/h2>\n<p>Con EclipseLink podemos crear consultas jer\u00e1rquicas limitadas, es una opci\u00f3n intermedia que nos puede ayudar a reducir el volumen de datos inicial sobre los que operar. La principal desventaja es que dependemos de EclipseLink.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Entidad Category<\/strong><\/p>\n<div>\n<pre>\r\n<span style=\"font-size:12px\"><span style=\"font-family:Courier New,Courier,monospace\">@Entity\r\npublic class Category {\r\n    @Id\r\n    private Long id;\r\n    \r\n    private String description;\r\n\r\n    @OneToOne(fetch = FetchType.LAZY)\r\n    @JoinColumn(name = \"PARENT_ID\", insertable = false, updatable = false)\r\n    private Category parent;\r\n\r\n    @OneToMany(mappedBy = \"parent\")\r\n    private Set&lt;Category&gt; children = new HashSet&lt;&gt;();\r\n\r\n    @Transient\r\n    public int getTreeLevel() {\r\n        int level = 1;\r\n        Category currentNode = this;\r\n\r\n        while (!currentNode.isRoot()) {\r\n            level++;\r\n            currentNode = currentNode.getParent();\r\n        }\r\n\r\n        return level;\r\n    }\r\n\r\n    @Transient\r\n    public boolean isRoot() {\r\n        return getParent() == null;\r\n    }\r\n}<\/span><\/span>\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p><strong>M\u00e9todo de consulta<\/strong><\/p>\n<div>\n<div>\n<pre>\r\n<span style=\"font-size:12px\"><span style=\"font-family:Courier New,Courier,monospace\">@SuppressWarnings(\"unchecked\")\r\npublic List&lt;Category&gt; findOnTree(Long fromNodeId, int maxLevel, List&lt;Long&gt; blackList)\r\n        throws IllegalStateException, SecurityException, SystemException {<\/span>\r\n\r\n<span style=\"font-family:Courier New,Courier,monospace\">    ExpressionBuilder builder = new ExpressionBuilder(Category.class);\r\n    Expression startWith = builder.get(\"id\").equal(fromNodeId);\r\n    Expression connectBy = builder.get(\"children\");<\/span>\r\n\r\n<span style=\"font-family:Courier New,Courier,monospace\">    ReadAllQuery query = new ReadAllQuery(Category.class);\r\n    query.setSelectionCriteria(\r\n            builder.get(\"id\").notIn(blackList).and(builder.get(\"parent\").notIn(blackList)));\r\n    query.setHierarchicalQueryClause(startWith, connectBy, null);<\/span>\r\n\r\n<span style=\"font-family:Courier New,Courier,monospace\">    List&lt;Category&gt; result = (List&lt;GgrlSapVOrganics&gt;) EntityManagerHelper\r\n            .entityManager()\r\n            .unwrap(UnitOfWork.class)\r\n            .executeQuery(query);<\/span>\r\n\r\n<span style=\"font-family:Courier New,Courier,monospace\">    return result.stream().filter(o -&gt; o.getTreeLevel() &lt;= maxLevel).collect(Collectors.toList());\r\n}<\/span><\/span><\/pre>\n<\/div>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Hay que tener en cuenta que esta opci\u00f3n no permite filtrar por \u201cnivel\u201d en BBDD, por lo que el bloque de datos traer\u00e1 todos los sub-nodos del nodo indicado con el \u201cstartWith\u201d. A cambio, nos permite filtrar a partir de un nodo concreto, y ordena el resultado teniendo en cuenta la jerarqu\u00eda.<\/p>\n<p>La clave est\u00e1&nbsp;en la <strong>ReadAllQuery.setHierarchicalQueryClause(&#8230;)<\/strong>, que proporciona EclipseLink y que se asemeja al concepto utilizado en al query nativa.<\/p>\n<h1>&nbsp;<\/h1>\n<h1>Conclusi\u00f3n<\/h1>\n<p>A la hora de decidir qu\u00e9 opci\u00f3n utilizamos en nuestros proyectos, tendremos que tener en cuenta la arquitectura que se utiliza, las restricciones del cliente y el tiempo del que disponemos para desarrollar.<\/p>\n<p>En general dir\u00eda que la mejor opci\u00f3n para estos casos es utilizar una vista de BBDD, siempre que esta vista sea suficientemente gen\u00e9rica y reutilizable, pero siempre es importante el contexto del proyecto, y es este quien nos marcar\u00e1 cu\u00e1l es la opci\u00f3n que debemos utilizar y la que mejor se adapta a la situaci\u00f3n.<\/p>\n<p>Os animo a dejar comentarios sobre otras soluciones, frameworks o librer\u00edas que conozc\u00e1is para filtrar objetos jerarqu\u00edcos.<\/p>\n<h5 class=\"rteright\" dir=\"ltr\">Foto de cap\u00e7alera de&nbsp;<a href=\"https:\/\/www.basetis.com\/\" target=\"_blank\" rel=\"noopener\">Basetis<\/a><\/h5>\n","protected":false},"excerpt":{"rendered":"<p>Introducci\u00f3n A veces una aplicaci\u00f3n necesita operar sobre datos jer\u00e1rquicos que se encuentran en una BBDD, es decir, tablas que tienen una relaci\u00f3n sobre s\u00ed&nbsp;mismas (del tipo categor\u00eda-subcategor\u00edas). Cuando las operaciones son sencillas no se necesita nada especial, pero en cuanto es necesario filtrar datos por niveles de la jerarqu\u00eda u obtener un nodo concreto [&hellip;]<\/p>\n","protected":false},"author":884,"featured_media":13900,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"","template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1562],"tags":[2815,1647,2814,1813,2813,1947],"etiquetes":[],"categorias":[],"class_list":["post-21946","article_basic","type-article_basic","status-publish","format-standard","has-post-thumbnail","hentry","category-tecnologia","tag-arbol","tag-java","tag-jerarquias","tag-open","tag-query","tag-soluciones"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Filtrar jerarqu\u00edas con Java - Basetis<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Filtrar jerarqu\u00edas con Java - Basetis\" \/>\n<meta property=\"og:description\" content=\"Introducci\u00f3n A veces una aplicaci\u00f3n necesita operar sobre datos jer\u00e1rquicos que se encuentran en una BBDD, es decir, tablas que tienen una relaci\u00f3n sobre s\u00ed&nbsp;mismas (del tipo categor\u00eda-subcategor\u00edas). Cuando las operaciones son sencillas no se necesita nada especial, pero en cuanto es necesario filtrar datos por niveles de la jerarqu\u00eda u obtener un nodo concreto [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/\" \/>\n<meta property=\"og:site_name\" content=\"Basetis\" \/>\n<meta property=\"article:modified_time\" content=\"2024-03-12T13:01:12+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blog.basetis.com\/wp-content\/uploads\/2022\/10\/java_0.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1\" \/>\n\t<meta property=\"og:image:height\" content=\"1\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data1\" content=\"5 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/blog.basetis.com\\\/es\\\/article_basic\\\/filtrar-jerarquias-con-java\\\/\",\"url\":\"https:\\\/\\\/blog.basetis.com\\\/es\\\/article_basic\\\/filtrar-jerarquias-con-java\\\/\",\"name\":\"Filtrar jerarqu\u00edas con Java - Basetis\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blog.basetis.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/blog.basetis.com\\\/es\\\/article_basic\\\/filtrar-jerarquias-con-java\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/blog.basetis.com\\\/es\\\/article_basic\\\/filtrar-jerarquias-con-java\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/blog.basetis.com\\\/wp-content\\\/uploads\\\/2022\\\/10\\\/java_0.png\",\"datePublished\":\"2022-10-14T09:35:34+00:00\",\"dateModified\":\"2024-03-12T13:01:12+00:00\",\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/blog.basetis.com\\\/es\\\/article_basic\\\/filtrar-jerarquias-con-java\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/blog.basetis.com\\\/es\\\/article_basic\\\/filtrar-jerarquias-con-java\\\/#primaryimage\",\"url\":\"https:\\\/\\\/blog.basetis.com\\\/wp-content\\\/uploads\\\/2022\\\/10\\\/java_0.png\",\"contentUrl\":\"https:\\\/\\\/blog.basetis.com\\\/wp-content\\\/uploads\\\/2022\\\/10\\\/java_0.png\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/blog.basetis.com\\\/#website\",\"url\":\"https:\\\/\\\/blog.basetis.com\\\/\",\"name\":\"Basetis\",\"description\":\"Testing\",\"publisher\":{\"@id\":\"https:\\\/\\\/blog.basetis.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/blog.basetis.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/blog.basetis.com\\\/#organization\",\"name\":\"Basetis\",\"url\":\"https:\\\/\\\/blog.basetis.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/blog.basetis.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/blog.basetis.com\\\/wp-content\\\/uploads\\\/2024\\\/02\\\/logo.svg\",\"contentUrl\":\"https:\\\/\\\/blog.basetis.com\\\/wp-content\\\/uploads\\\/2024\\\/02\\\/logo.svg\",\"width\":187,\"height\":29,\"caption\":\"Basetis\"},\"image\":{\"@id\":\"https:\\\/\\\/blog.basetis.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Filtrar jerarqu\u00edas con Java - Basetis","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/","og_locale":"es_ES","og_type":"article","og_title":"Filtrar jerarqu\u00edas con Java - Basetis","og_description":"Introducci\u00f3n A veces una aplicaci\u00f3n necesita operar sobre datos jer\u00e1rquicos que se encuentran en una BBDD, es decir, tablas que tienen una relaci\u00f3n sobre s\u00ed&nbsp;mismas (del tipo categor\u00eda-subcategor\u00edas). Cuando las operaciones son sencillas no se necesita nada especial, pero en cuanto es necesario filtrar datos por niveles de la jerarqu\u00eda u obtener un nodo concreto [&hellip;]","og_url":"https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/","og_site_name":"Basetis","article_modified_time":"2024-03-12T13:01:12+00:00","og_image":[{"url":"https:\/\/blog.basetis.com\/wp-content\/uploads\/2022\/10\/java_0.png","width":1,"height":1,"type":"image\/png"}],"twitter_card":"summary_large_image","twitter_misc":{"Tiempo de lectura":"5 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/","url":"https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/","name":"Filtrar jerarqu\u00edas con Java - Basetis","isPartOf":{"@id":"https:\/\/blog.basetis.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/#primaryimage"},"image":{"@id":"https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/#primaryimage"},"thumbnailUrl":"https:\/\/blog.basetis.com\/wp-content\/uploads\/2022\/10\/java_0.png","datePublished":"2022-10-14T09:35:34+00:00","dateModified":"2024-03-12T13:01:12+00:00","inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/blog.basetis.com\/es\/article_basic\/filtrar-jerarquias-con-java\/#primaryimage","url":"https:\/\/blog.basetis.com\/wp-content\/uploads\/2022\/10\/java_0.png","contentUrl":"https:\/\/blog.basetis.com\/wp-content\/uploads\/2022\/10\/java_0.png"},{"@type":"WebSite","@id":"https:\/\/blog.basetis.com\/#website","url":"https:\/\/blog.basetis.com\/","name":"Basetis","description":"Testing","publisher":{"@id":"https:\/\/blog.basetis.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.basetis.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/blog.basetis.com\/#organization","name":"Basetis","url":"https:\/\/blog.basetis.com\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/blog.basetis.com\/#\/schema\/logo\/image\/","url":"https:\/\/blog.basetis.com\/wp-content\/uploads\/2024\/02\/logo.svg","contentUrl":"https:\/\/blog.basetis.com\/wp-content\/uploads\/2024\/02\/logo.svg","width":187,"height":29,"caption":"Basetis"},"image":{"@id":"https:\/\/blog.basetis.com\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/article_basic\/21946","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/article_basic"}],"about":[{"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/types\/article_basic"}],"author":[{"embeddable":true,"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/users\/884"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/comments?post=21946"}],"version-history":[{"count":1,"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/article_basic\/21946\/revisions"}],"predecessor-version":[{"id":21947,"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/article_basic\/21946\/revisions\/21947"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/media\/13900"}],"wp:attachment":[{"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/media?parent=21946"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/categories?post=21946"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/tags?post=21946"},{"taxonomy":"etiquetes","embeddable":true,"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/etiquetes?post=21946"},{"taxonomy":"categorias","embeddable":true,"href":"https:\/\/blog.basetis.com\/es\/wp-json\/wp\/v2\/categorias?post=21946"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}