{"id":14562,"date":"2023-06-23T13:15:52","date_gmt":"2023-06-23T20:15:52","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=14562"},"modified":"2024-03-01T09:01:33","modified_gmt":"2024-03-01T17:01:33","slug":"recursive-query-processing-in-sql-n1ql","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/recursive-query-processing-in-sql-n1ql\/","title":{"rendered":"Procesamiento recursivo de consultas en SQL++ (N1QL)"},"content":{"rendered":"<p><span style=\"font-weight: 400\">Es muy probable que se haya encontrado con problemas con <\/span><b>b\u00fasquedas jer\u00e1rquicas o navegaci\u00f3n por grafos<\/b><span style=\"font-weight: 400\"> en tu aplicaci\u00f3n como desarrollador que maneja casos de uso del mundo real. Y, por razones obvias, prefieres resolverlos en el <\/span><b>base de datos y no en el cliente<\/b><span style=\"font-weight: 400\">.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">\u00bfQu\u00e9 son las b\u00fasquedas jer\u00e1rquicas?<\/span><\/h2>\n<p><span style=\"font-weight: 400\">La b\u00fasqueda jer\u00e1rquica hace referencia al proceso de b\u00fasqueda y recuperaci\u00f3n de datos de una estructura jer\u00e1rquica, como una <\/span><b>\u00e1rbol o una relaci\u00f3n padre-hijo<\/b><span style=\"font-weight: 400\">. Implica navegar por los niveles o capas de la jerarqu\u00eda para localizar elementos de datos espec\u00edficos o informaci\u00f3n relacionada, por ejemplo, organigramas, sistemas de archivos y \u00e1rboles de categor\u00edas.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Los grafos son b\u00e1sicamente \u00e1rboles que pueden tener ciclos, por lo que, adem\u00e1s, tambi\u00e9n podr\u00edamos cubrir casos de uso como la b\u00fasqueda de rutas, etc. siempre que dispongamos de configuraciones adicionales para tratar los ciclos.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-14566\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_124236084.png\" alt=\"hierachical lookups\" width=\"1019\" height=\"679\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124236084.png 1019w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124236084-300x200.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124236084-768x512.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124236084-400x267.png 400w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124236084-450x300.png 450w\" sizes=\"auto, (max-width: 1019px) 100vw, 1019px\" \/><\/p>\n<p><span style=\"font-weight: 400\">Considere un ejemplo en el que se utiliza una colecci\u00f3n de empleados con una estructura jer\u00e1rquica. Los empleados est\u00e1n organizados en una relaci\u00f3n gerente-subordinado. Vamos a realizar operaciones en esta jerarqu\u00eda de empleados usando Couchbase y JavaScript UDFs para demostrar la soluci\u00f3n.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Pasando de la <\/span><i><span style=\"font-weight: 400\">Recogida de empleados <\/span><\/i><span style=\"font-weight: 400\">que podemos recuperar:<\/span><\/p>\n<p><span style=\"font-weight: 400\">i) nivel gen\u00e9rico de empleado:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-14567\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_124344227-1024x555.png\" alt=\"\" width=\"900\" height=\"488\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124344227-1024x555.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124344227-300x163.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124344227-768x416.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124344227.png 1238w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p><span style=\"font-weight: 400\">ii) jerarqu\u00eda para cada empleado:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-14568\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_124413697-1024x379.png\" alt=\"\" width=\"900\" height=\"333\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124413697-1024x379.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124413697-300x111.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124413697-768x284.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124413697.png 1296w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<h2><span style=\"font-weight: 400\">De qu\u00e9 trata este blog<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Realmente te gusta el <\/span><b>flexibilidad<\/b><span style=\"font-weight: 400\"> de bases de datos NoSQL, y su modelo de datos subyacente es <\/span><b>JSON, <\/b><span style=\"font-weight: 400\">por eso ha elegido Couchbase para sus necesidades de base de datos (gran elecci\u00f3n, por cierto :-) ).<\/span><\/p>\n<p><span style=\"font-weight: 400\">Ahora que tienes Couchbase como base de datos, quieres resolver el problema mencionado. Despu\u00e9s de investigar un poco en <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/es\/sqlplusplus\/\"><span style=\"font-weight: 400\">SQL<\/span><\/a><span style=\"font-weight: 400\"> Documentos de referencia ling\u00fc\u00edstica<\/span><span style=\"font-weight: 400\"> ha llegado a la conclusi\u00f3n de que no hay <\/span><i><span style=\"font-weight: 400\">Declaraci\u00f3n <\/span><\/i><span style=\"font-weight: 400\">o <\/span><i><span style=\"font-weight: 400\">Funci\u00f3n <\/span><\/i><span style=\"font-weight: 400\">en SQL++ para resolver nuestro problema, como el <\/span><a href=\"https:\/\/www.mongodb.com\/docs\/manual\/reference\/operator\/aggregation\/graphLookup\/?_ga=2.234064094.1723037650.1675387315-1783168968.1675058199#-graphlookup--aggregation-\"><span style=\"font-weight: 400\">graphLookup<\/span><\/a><span style=\"font-weight: 400\"> API en MongoDB o <\/span><a href=\"https:\/\/docs.snowflake.com\/en\/user-guide\/queries-cte#recursive-ctes-and-hierarchical-data\"><span style=\"font-weight: 400\">CTE recursivo<\/span><\/a><span style=\"font-weight: 400\"> en bases de datos SQL.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Pero <\/span><b>con la infraestructura existente, los usuarios pueden emular CTE recursivos utilizando UDF de JavaScript. <\/b><span style=\"font-weight: 400\">En las secciones siguientes se explica c\u00f3mo hacerlo y mucho m\u00e1s.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Soluci\u00f3n a las consultas recursivas<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Para implementar esta soluci\u00f3n, necesitamos crear un UDF de JavaScript que utilice un algoritmo de b\u00fasqueda breadth-first para recorrer la jerarqu\u00eda de empleados. La UDF toma un <\/span><b>consulta de anclaje<\/b><span style=\"font-weight: 400\">, a <\/span><b>consulta recursiva<\/b><span style=\"font-weight: 400\">y <\/span><b>opciones de configuraci\u00f3n como par\u00e1metros<\/b><span style=\"font-weight: 400\">. La consulta de anclaje recupera el conjunto inicial de empleados, mientras que la consulta recursiva hace referencia a los resultados de la iteraci\u00f3n anterior utilizando la funci\u00f3n <\/span><i><span style=\"font-weight: 400\">$1<\/span><\/i><span style=\"font-weight: 400\"> par\u00e1metro. Las opciones de configuraci\u00f3n permiten la personalizaci\u00f3n, incluidos los criterios de salida anticipada, los argumentos para las consultas internas, la detecci\u00f3n de ciclos, el modo de explicaci\u00f3n para la planificaci\u00f3n de consultas y las opciones de registro.<\/span><\/p>\n<h3>C\u00f3mo utilizar las consultas internas<\/h3>\n<p><span style=\"font-weight: 400\">La consulta de anclaje obtiene el <\/span><b>documentos de nivel ra\u00edz<\/b><span style=\"font-weight: 400\"> de la colecci\u00f3n de destino.<\/span><\/p>\n<p><span style=\"font-weight: 400\">La consulta recursiva puede utilizar un <\/span><i><span style=\"font-weight: 400\">\u00daNASE A <\/span><\/i><span style=\"font-weight: 400\">con un lado como <\/span><i><span style=\"font-weight: 400\">$1<\/span><\/i><span style=\"font-weight: 400\"> y la otra como colecci\u00f3n de destino, para explotar la relaci\u00f3n padre-hijo y realizar el recorrido de un nivel a otro.<\/span><\/p>\n<p><span style=\"font-weight: 400\">En nuestra funci\u00f3n, <\/span><i><span style=\"font-weight: 400\">$1<\/span><\/i><span style=\"font-weight: 400\"> hace lo mismo que el alias CTE en CTE recursivo.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Para comprender mejor c\u00f3mo utilizamos SQL++ (N1QL) en las UDF de JavaScript, eche un vistazo a<\/span> <a href=\"https:\/\/www.couchbase.com\/blog\/es\/from-n1ql-to-javascript-and-back-part-1-introduction\/\"><span style=\"font-weight: 400\">De N1QL a JavaScript y viceversa<\/span><\/a><span style=\"font-weight: 400\">.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Veamos ahora el proceso paso a paso. En primer lugar, <\/span><b>\u00bfes realmente necesario que el procesamiento recursivo de consultas sea una funci\u00f3n recursiva?<\/b><\/p>\n<p><span style=\"font-weight: 400\">No, esta ser\u00eda una mala elecci\u00f3n teniendo en cuenta la complejidad temporal (la misma funcionalidad en recursivo podr\u00eda ser exponencial, pero lineal en un enfoque iterativo) y todas las dem\u00e1s cuestiones como marcos, etc., que vienen junto con la recursividad. Si est\u00e1s interesado, echa un vistazo a esto <\/span><a href=\"https:\/\/www.baeldung.com\/cs\/convert-recursion-to-iteration\"><span style=\"font-weight: 400\">art\u00edculo<\/span><\/a><span style=\"font-weight: 400\"> sobre la conversi\u00f3n de funciones de recursividad de cola a iterativas. Adem\u00e1s, las UDF de JS tienen un preajuste <\/span><b>profundidad de recursi\u00f3n m\u00e1xima de 128;<\/b><span style=\"font-weight: 400\"> esto no es preferible para lo que intentamos hacer. <\/span><\/p>\n<p><span style=\"font-weight: 400\">En pocas palabras, cualquier tarea iterativa hace lo siguiente:<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-14569\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_124659049-1024x439.png\" alt=\"\" width=\"900\" height=\"386\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124659049-1024x439.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124659049-300x129.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124659049-768x330.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124659049.png 1235w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p><span style=\"font-weight: 400\">Nos gustar\u00eda agradecer este <\/span><a href=\"https:\/\/www.postgresql.org\/docs\/current\/queries-with.html\"><span style=\"font-weight: 400\">art\u00edculo<\/span><\/a><span style=\"font-weight: 400\"> por su planteamiento.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Puntos de reflexi\u00f3n<\/span><\/h2>\n<p><span style=\"font-weight: 400\">\u00bfC\u00f3mo mantenemos la <\/span><b>expresi\u00f3n de estado<\/b><span style=\"font-weight: 400\"> y pasarlo como par\u00e1metro a la consulta (parte recursiva aqu\u00ed)?<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Utilizamos la capacidad de SQL++ para pasar <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-intro\/queriesandresults.html#named-placeholders\"><span style=\"font-weight: 400\">par\u00e1metros de consulta din\u00e1micos<\/span><\/a><span style=\"font-weight: 400\"> y utilizar consultas parametrizadas para mantener el valor del estado en todos los niveles.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Utilizamos <\/span><em>$1<\/em> en la cl\u00e1usula recursiva para referirse a los resultados de iteraciones anteriores, es decir, la expresi\u00f3n de estado<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong>\u00bfC\u00f3mo podemos optimizar?<\/strong><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Preparar inicialmente tanto las consultas ancla como las recursivas para poder reutilizar los planes de consulta en el momento de la ejecuci\u00f3n.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Encontrar una manera de mirar el plan de consulta( similar a un <\/span><i><span style=\"font-weight: 400\">EXPLICAR<\/span><\/i><span style=\"font-weight: 400\"> ) para que podamos generar \u00edndices apropiados para las sentencias internas (ancla y recursivas).<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>El resumen de alto nivel de la aplicaci\u00f3n es el siguiente:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-14570\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_124838894-1024x659.png\" alt=\"\" width=\"900\" height=\"579\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124838894-1024x659.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124838894-300x193.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124838894-768x494.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_124838894.png 1294w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<h3><span style=\"font-weight: 400\">C\u00f3digo para CTE recursivo utilizando JS UDFs\u00a0<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Se trata de una implementaci\u00f3n muy ingenua para empezar a funcionar. Configuramos el <em>B\u00fasqueda exhaustiva<\/em> estableciendo el flujo de \u00f3rdenes seg\u00fan el resumen anterior. Aqu\u00ed est\u00e1 el c\u00f3digo, de <\/span><a href=\"https:\/\/gist.github.com\/GauravJayaraj\/2d290f5398efe6edb8dc1b53e87556ae\"><span style=\"font-weight: 400\">este Gist<\/span><\/a><span style=\"font-weight: 400\"> enlace:<\/span><\/p>\n<pre class=\"height-set:true nums:false lang:js decode:true\">function recursive_cte(anchor , recursive, config) {\r\n    let isLog = false;\r\n    let anchorArgs=[];\r\n    let recursiveArgs=[];\r\n    let cycleFields=[];\r\n    let hash;    \r\n    let levelLimit = -1;\r\n    let isExplain = false;\r\n\r\n    let res = {\"res\":[], \"log\":[]}\r\n\r\n\r\n    if(config!=undefined) {\r\n        if(config.log!=undefined &amp;&amp; config.log==true) {\r\n            isLog = true;\r\n        }\r\n\r\n        if(config.anchorArgs!=undefined) {\r\n            anchorArgs = config.anchorArgs;\r\n        }\r\n\r\n        if(config.recursiveArgs!=undefined) {\r\n            recursiveArgs = config.recursiveArgs;\r\n        }\r\n\r\n        if(config.levelLimit!=undefined &amp;&amp; config.levelLimit&gt;0) {\r\n            levelLimit = config.levelLimit;\r\n        }\r\n\r\n        if(config.cycleFields!=undefined &amp;&amp; config.cycleFields.length&gt;0) {\r\n            res['log'].push(\"Got cycle fields \"+ config.cycleFields)\r\n            \/\/ for(const field of config.cycleFields) {\r\n            \/\/     cycleFields.push(field);\r\n            \/\/ }\r\n            cycleFields = config.cycleFields;\r\n            res['log'].push(cycleFields);\r\n            \/\/ init hash\r\n            hash = createhash();\r\n\r\n        }\r\n\r\n        if(config.explain!=undefined) {\r\n            isExplain = true;\r\n        }\r\n\r\n    }\r\n    \r\n\r\n    \/\/ init state\r\n    recursiveArgs.push(0);\r\n    \r\n    \/\/ Prepare anchor statement\r\n    let anchorPname;\r\n    let anchorPlan;\r\n    try{\r\n        const anchor_prep = N1QL(\"PREPARE FORCE \"+anchor);\r\n        \r\n        for(const ap of anchor_prep) {\r\n            anchorPname = ap[\"name\"];\r\n            anchorPlan = ap[\"operator\"];\r\n        }\r\n\r\n        res['log'].push(\"prepared anchor\");\r\n    }\r\n    catch(err) {\r\n        res['log'].push(\"couldn't prepare anchor\");\r\n        throw err;\r\n    }\r\n\r\n     \/\/ prepare recursive statement\r\n\r\n     let recursivePname;\r\n     let recursivePlan;\r\n     try{\r\n         const recursive_prep = N1QL(\"PREPARE FORCE \"+recursive);\r\n \r\n         for(const rp of recursive_prep) {\r\n             recursivePname = rp[\"name\"];\r\n             recursivePlan = rp[\"operator\"];\r\n         }\r\n         res['log'].push(\"prepared recursive\");\r\n     }\r\n     catch(err) {\r\n         res['log'].push(\"couldn't prepare recursive\");\r\n         throw err;\r\n     }\r\n\r\n\r\n    \/\/ state expression \r\n    let workSet = []\r\n\r\n    \/\/ execute anchor \r\n    try{\r\n        const anchorExec = N1QL(\"EXECUTE `\"+anchorPname+\"`\",anchorArgs);\r\n        for(const doc of anchorExec) {\r\n            workSet.push(doc);\r\n        }\r\n    }\r\n    catch(err) {\r\n        res['log'].push(\"failed to execute anchor\");\r\n        throw err;\r\n    }\r\n\r\n    \/\/ cycle check\r\n    if(cycleFields.length&gt;0) {\r\n        res['log'].push(\"cycle check on fields \"+cycleFields)\r\n        workSet = cycleCheck(cycleFields, hash, workSet);\r\n    }\r\n\r\n    \/\/ populate root level( level 0 )\r\n    res['res'].push(...workSet);\r\n\r\n\r\n    let level = 0;\r\n\r\n    while(workSet.length!=0) {\r\n\r\n        \/\/ exit on level condition\r\n        if(levelLimit&gt;0 &amp;&amp; level&gt;=levelLimit) {\r\n            res['log'].push(\"Exit on level condition: levelLimit=\"+levelLimit.toString())\r\n            break;\r\n        }\r\n\r\n        \/\/ execute recursive query\r\n        let newWorkSet = []\r\n\r\n        \/\/ set state $1\r\n        recursiveArgs[0] = workSet;\r\n\r\n        try{\r\n            const recursiveExec = N1QL(\"EXECUTE `\"+recursivePname+\"`\", recursiveArgs)\r\n\r\n            \/\/ empty workSet to populate again\r\n            for(const doc of recursiveExec) {\r\n                newWorkSet.push(doc)\r\n            }\r\n        }\r\n        catch(err){\r\n            res['log'].push(\"failed execute recursive\");\r\n            throw err;\r\n        }\r\n\r\n        \/\/ cycle check\r\n        if(cycleFields.length&gt;0) {\r\n            newWorkSet = cycleCheck(cycleFields, hash, newWorkSet);\r\n        }\r\n\r\n        if(newWorkSet.length==0)\r\n            break;\r\n\r\n        \r\n        res[\"res\"].push(...newWorkSet);\r\n\r\n        \/\/ update state expression\r\n        workSet = newWorkSet;\r\n\r\n        level++;\r\n    }\r\n\r\n    if(isExplain){\r\n        res['log'].push(\"Anchor Plan:\");\r\n        res['log'].push(anchorPlan);\r\n        res['log'].push(\"Recursive Plan\");\r\n        res[\"log\"].push(recursivePlan);\r\n        return res;\r\n    }\r\n\r\n    return isLog?res:res['res'];\r\n}\r\n\r\n\r\nfunction createhash() {\r\n    let h = {};\r\n\r\n    const getVal = function(key) {\r\n        return h[key]==undefined?false:true;\r\n    }\r\n\r\n    const setVal = function(key) {\r\n        h[key] = true;\r\n    }\r\n\r\n    return {setVal, getVal};\r\n}\r\n\r\nfunction cycleCheck(cycleFields, hash, workSet) {\r\n    let cycleTrim = [];\r\n    for(const doc of workSet) {\r\n        let key = [];\r\n        for(const field of cycleFields) {\r\n            if(doc[field]!=undefined){\r\n                key.push(String(doc[field]));\r\n            }\r\n        }\r\n\r\n        \/\/ create hashKey\r\n        hashKey = key.join(String.fromCharCode(30));\r\n\r\n\r\n        if(hash.getVal(hashKey)==true){\r\n            continue;\r\n        }\r\n        else{\r\n            hash.setVal(hashKey);\r\n            cycleTrim.push(doc);\r\n        }\r\n    }\r\n\r\n    return cycleTrim;\r\n}\r\n<\/pre>\n<h3>C\u00f3mo a\u00f1adir la funci\u00f3n<\/h3>\n<p><span style=\"font-weight: 400\">He aqu\u00ed una <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/guides\/create-javascript-library.html\"><span style=\"font-weight: 400\">enlace<\/span><\/a><span style=\"font-weight: 400\"> para a\u00f1adirlo a una biblioteca JavaScript (por ejemplo <\/span><em>\"mi biblioteca\"<\/em><span style=\"font-weight: 400\">) dentro de su servicio de consulta, y un <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/guides\/create-user-defined-function.html\"><span style=\"font-weight: 400\">enlace<\/span><\/a><span style=\"font-weight: 400\"> para crear la UDF a partir de la biblioteca a\u00f1adida.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Cree la UDF desde la biblioteca utilizando SQL++: <\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION recursiveCte(anchor, recursive, config)\r\nLANGUAGE JAVASCRIPT as \"recursive_cte\" AT \"mylibrary\";\r\n<\/pre>\n<p><b>Utilizaci\u00f3n<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">Argumento 1: <em>Ancla<\/em> consulta, cadena<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\">Argumento 2: <em>Recursivo<\/em> consulta, cadena <\/span><span style=\"font-weight: 400\">(usos <\/span><i><span style=\"font-weight: 400\">$1(expresi\u00f3n del estado)<\/span><\/i><span style=\"font-weight: 400\"> para referirse a los resultados de la iteraci\u00f3n anterior )<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\">Argumento 3: Config <em>opciones<\/em>objeto<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\">Todos son <\/span><b>obligatorio<\/b><span style=\"font-weight: 400\">pero puede pasar un <\/span><i><span style=\"font-weight: 400\">objeto vac\u00edo<\/span><\/i><span style=\"font-weight: 400\">es decir, <\/span><i><span style=\"font-weight: 400\">{}<\/span><\/i><span style=\"font-weight: 400\"> si no est\u00e1 utilizando ninguna opci\u00f3n de configuraci\u00f3n.<\/span><\/p>\n<p><span style=\"font-weight: 400\"><br \/>\n<\/span><b>Opciones de configuraci\u00f3n<\/b><b><\/b><\/p>\n<p style=\"padding-left: 40px\"><b>Salida anticipada<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>levelLimit<\/em>(1 a N) - Especifica el nivel en el que podemos parar. El recuento de niveles comienza en <\/span><i><span style=\"font-weight: 400\">0<\/span><\/i><span style=\"font-weight: 400\"> para obtener resultados de anclaje, <\/span><i><span style=\"font-weight: 400\">1<\/span><\/i><span style=\"font-weight: 400\"> para la primera iteraci\u00f3n\/nivel, <\/span><i><span style=\"font-weight: 400\">2<\/span><\/i><span style=\"font-weight: 400\"> para el segundo, etc.<\/span><\/p>\n<p style=\"padding-left: 40px\"><b>Argumentos de la consulta interna<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>anchorArgs<\/em> - como se nombra, por ejemplo,<\/span><i><span style=\"font-weight: 400\">{\"arg:1}<\/span><\/i><span style=\"font-weight: 400\"> o argumentos posicionales, por ejemplo <\/span><i><span style=\"font-weight: 400\">[1]<\/span><\/i><span style=\"font-weight: 400\"> para utilizar en la consulta de anclaje.<\/span><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>recursiveArgs<\/em> - s\u00f3lo pueden ser argumentos posicionales, y <\/span><i><span style=\"font-weight: 400\">0<\/span><\/i><span style=\"font-weight: 400\"> debe reservarse para la expresi\u00f3n de estado. Por ejemplo: <\/span><i><span style=\"font-weight: 400\">[0, 1] <\/span><\/i><span style=\"font-weight: 400\">- fijar siempre el \u00edndice 0 (<\/span><i><span style=\"font-weight: 400\">$1<\/span><\/i><span style=\"font-weight: 400\"> arg) a <\/span><i><span style=\"font-weight: 400\">0<\/span><\/i><span style=\"font-weight: 400\">por lo que podemos utilizarla en la cl\u00e1usula recursiva como expresi\u00f3n de estado.<\/span><\/p>\n<p style=\"padding-left: 40px\"><b>Detecci\u00f3n de ciclo<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>cycleFields<\/em> - Matriz de nombres de campo, por ejemplo, <\/span><i><span style=\"font-weight: 400\">[\"_de\", \"_a\"]<\/span><\/i><\/p>\n<p style=\"padding-left: 40px\"><b>Explique<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>explique<\/em> - Comprobar el plan de consulta en los registros (conjuntos <\/span><i><span style=\"font-weight: 400\">registro <\/span><\/i><span style=\"font-weight: 400\">por defecto)<\/span><\/p>\n<p style=\"padding-left: 40px\"><b>Registros<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>registro<\/em> - Visualizar registros que ayudan cuando se quiere registrar mientras se desarrolla<\/span><\/p>\n<p>&nbsp;<\/p>\n<h2><span style=\"font-weight: 400\">Ejemplos de consultas<\/span><\/h2>\n<p><span style=\"font-weight: 400\"><br \/>\n<\/span><b>1.<\/b><span style=\"font-weight: 400\"> <b>Contar n\u00fameros del 1 al N<\/b> - ejemplo m\u00e1s sencillo de una consulta que muestra c\u00f3mo funciona la CTE recursiva.<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\">\u00a0 \u00a0\u00a0<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span> <span style=\"font-weight: 400\">Haz una breve pausa para pensar c\u00f3mo podr\u00edas hacer esto en N1QL sin la funci\u00f3n <\/span><span style=\"font-weight: 400\">utilidad que desarrollamos ahora. \u00bfEs posible? (\u00bfO acabamos de hacer<\/span><b> N1QL \u00a1Turing completo!<\/b><span style=\"font-weight: 400\">)<br \/>\n<\/span><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-14571\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_125658889-1024x444.png\" alt=\"\" width=\"900\" height=\"390\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125658889-1024x444.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125658889-300x130.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125658889-768x333.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125658889.png 1269w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p><b>2. Ejemplo de empleados<\/b> - se refieren a la colecci\u00f3n de empleados que vimos antes.<\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">A. Encontrar el nivel organizativo de un empleado<\/span><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-14572\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_125805870-1024x424.png\" alt=\"\" width=\"900\" height=\"373\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125805870-1024x424.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125805870-300x124.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125805870-768x318.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125805870.png 1251w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p style=\"padding-left: 40px\">B. <span style=\"font-weight: 400\">Por empleado depende de la jerarqu\u00eda<\/span><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-14573\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_125914592-1024x580.png\" alt=\"\" width=\"900\" height=\"510\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125914592-1024x580.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125914592-300x170.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125914592-768x435.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_125914592.png 1225w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p><span style=\"font-weight: 400\">Consulta de anclaje: <\/span><\/p>\n<pre class=\"lang:default decode:true\">SELECT e1.*, 0 como hlevel\r\nFROM `empleados` e1\r\nWHERE e1.manager_id=\" || to_str(e.employee_id)<\/pre>\n<p>Esto puede parecer demasiado verboso cuando se a\u00f1ade un <em>DONDE<\/em> predicado de la consulta externa.  W<span style=\"font-weight: 400\">e puede utilizar el <\/span><em>anchorArgs<\/em> opci\u00f3n<span style=\"font-weight: 400\"> \u00a1para mitigarlo!<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Argumentos (anchorArgs\/recursiveArgs)<\/span><\/h3>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-14574\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_130029549-1024x191.png\" alt=\"\" width=\"900\" height=\"168\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130029549-1024x191.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130029549-300x56.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130029549-768x143.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130029549.png 1253w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p style=\"padding-left: 40px\"><strong>Explique<\/strong><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">Proporcione <\/span><span style=\"font-weight: 400\">{\"explain\": true} - <\/span><span style=\"font-weight: 400\">puede ver el plan de consulta en el campo de registro\u00a0<\/span><\/p>\n<p style=\"padding-left: 40px\"><strong>Salida anticipada<\/strong><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">Establecer <\/span><i><span style=\"font-weight: 400\">levelLimit <\/span><\/i><span style=\"font-weight: 400\">como <\/span><i><span style=\"font-weight: 400\">{\"levelLimit\":2}<\/span><\/i><span style=\"font-weight: 400\"> - si s\u00f3lo desea 2 niveles de recursividad<\/span><\/p>\n<p>&nbsp;<\/p>\n<p style=\"padding-left: 40px\"><strong>Detecci\u00f3n del ciclo<\/strong><\/p>\n<p style=\"padding-left: 40px\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-14575\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_130205451-1024x334.png\" alt=\"\" width=\"900\" height=\"294\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130205451-1024x334.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130205451-300x98.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130205451-768x250.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130205451.png 1271w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p style=\"padding-left: 40px\"><b>Sin detecci\u00f3n de ciclo <\/b><span style=\"font-weight: 400\">la consulta para encontrar la jerarqu\u00eda de nivel de empleado ir\u00e1 a un <\/span><b>bucle infinito <\/b><i><span style=\"font-weight: 400\">y se bloquean al agotarse el tiempo de espera de la funci\u00f3n, desperdiciando recursos de la CPU.<\/span><\/i><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\">Teniendo en cuenta que cuando trabajamos con datos gr\u00e1ficos es muy probable que tengamos ciclos presentes y es el <\/span><b>responsabilidad de la persona que llama a la funci\u00f3n para establecer la detecci\u00f3n de ciclo de los campos apropiados.<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">Aqu\u00ed, el <\/span><i><span style=\"font-weight: 400\">\"employee_id\"<\/span><\/i><span style=\"font-weight: 400\">, <\/span><i><span style=\"font-weight: 400\">\"manager_id\"<\/span><\/i><span style=\"font-weight: 400\">\u00a0 es suficiente para salir en ciclo.<\/span><\/p>\n<p style=\"padding-left: 40px\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-14576\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/image_2023-06-23_130306815-1024x312.png\" alt=\"\" width=\"900\" height=\"274\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130306815-1024x312.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130306815-300x92.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130306815-768x234.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/image_2023-06-23_130306815.png 1259w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p>Gracias por seguirnos en este desafiante tema, \u00a1esperamos que te revele m\u00e1s opciones para algunos de tus retos de consulta recursiva!<\/p>\n<h2><span style=\"font-weight: 400\">Referencias<\/span><\/h2>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.baeldung.com\/cs\/convert-recursion-to-iteration\"><span style=\"font-weight: 400\">Convertir funciones recursivas en iterativas (Baeldung)<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/index.html\"><span style=\"font-weight: 400\">Documentaci\u00f3n de referencia del lenguaje SQL<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.mongodb.com\/docs\/manual\/reference\/operator\/aggregation\/graphLookup\/?_ga=2.234064094.1723037650.1675387315-1783168968.1675058199#-graphlookup--aggregation-\"><span style=\"font-weight: 400\">Referencia de MongoDB graphLookup<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.snowflake.com\/en\/user-guide\/queries-cte#recursive-ctes-and-hierarchical-data\"><span style=\"font-weight: 400\">Referencia CTE recursiva Snowflake<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.couchbase.com\/blog\/es\/from-n1ql-to-javascript-and-back-part-1-introduction\/\"><span style=\"font-weight: 400\">Blog: De N1QL a JavaScript y viceversa - Parte 1<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.postgresql.org\/docs\/current\/queries-with.html\"><span style=\"font-weight: 400\">Referencia de consulta PostgreSQL, cl\u00e1usula WITH<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-intro\/queriesandresults.html#named-placeholders\"><span style=\"font-weight: 400\">Documentaci\u00f3n sobre consultas y resultados en SQL<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.couchbase.com\/server\/current\/guides\/create-javascript-library.html\"><span style=\"font-weight: 400\">Creaci\u00f3n de una biblioteca JavaScript docs<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.couchbase.com\/server\/current\/guides\/create-user-defined-function.html\"><span style=\"font-weight: 400\">Creaci\u00f3n de funciones definidas por el usuario (UDF) en Couchbase<\/span><\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>It is extremely likely that you have come across issues with hierarchical lookups or graph traversal in your application as a developer who handles real-world use cases. And, for obvious reasons, you prefer solving them at the database layer and [&hellip;]<\/p>","protected":false},"author":84423,"featured_media":14577,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1816,1819,9327,1812],"tags":[9836,8911],"ppma_author":[9835],"class_list":["post-14562","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-couchbase-server","category-data-modeling","category-javascript","category-n1ql-query","tag-recursive-queries","tag-udf"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.7.1 (Yoast SEO v25.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Recursive Query Processing in SQL++ (N1QL) Function<\/title>\n<meta name=\"description\" content=\"Users can emulate recursive CTE using JavaScript UDFs with existing infrastructure. This Couchbase blog post demonstrates just how to do that and more!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/es\/recursive-query-processing-in-sql-n1ql\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Recursive Query Processing in SQL++ (N1QL)\" \/>\n<meta property=\"og:description\" content=\"Users can emulate recursive CTE using JavaScript UDFs with existing infrastructure. This Couchbase blog post demonstrates just how to do that and more!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/recursive-query-processing-in-sql-n1ql\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-06-23T20:15:52+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-03-01T17:01:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/remy-penet-zaM9LhySx_0-unsplash-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"2560\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Gaurav Jayaraj - Software Engineer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Gaurav Jayaraj - Software Engineer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/\"},\"author\":{\"name\":\"Gaurav Jayaraj - Software Engineer\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/546cec92f77cbb0b09f9b973fd1c8d42\"},\"headline\":\"Recursive Query Processing in SQL++ (N1QL)\",\"datePublished\":\"2023-06-23T20:15:52+00:00\",\"dateModified\":\"2024-03-01T17:01:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/\"},\"wordCount\":1232,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/remy-penet-zaM9LhySx_0-unsplash-scaled.jpg\",\"keywords\":[\"recursive queries\",\"User Defined Function (UDF)\"],\"articleSection\":[\"Couchbase Server\",\"Data Modeling\",\"JavaScript\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/\",\"name\":\"Recursive Query Processing in SQL++ (N1QL) Function\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/remy-penet-zaM9LhySx_0-unsplash-scaled.jpg\",\"datePublished\":\"2023-06-23T20:15:52+00:00\",\"dateModified\":\"2024-03-01T17:01:33+00:00\",\"description\":\"Users can emulate recursive CTE using JavaScript UDFs with existing infrastructure. This Couchbase blog post demonstrates just how to do that and more!\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/remy-penet-zaM9LhySx_0-unsplash-scaled.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/remy-penet-zaM9LhySx_0-unsplash-scaled.jpg\",\"width\":1920,\"height\":2560,\"caption\":\"Fibonacci design of staircase by Remy Penet on Unsplash\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Recursive Query Processing in SQL++ (N1QL)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/546cec92f77cbb0b09f9b973fd1c8d42\",\"name\":\"Gaurav Jayaraj - Software Engineer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/a332e5d7f47865015367ca88af3e5891\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/02\/unnamed-2.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/02\/unnamed-2.jpg\",\"caption\":\"Gaurav Jayaraj - Software Engineer\"},\"description\":\"Gaurav Jayaraj is an intern in the Query team at Couchbase R&amp;D. Gaurav is pursuing his Bachelors in Computer Science from PES University, Bangalore.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/gauravjayaraj\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Recursive Query Processing in SQL++ (N1QL) Function","description":"Users can emulate recursive CTE using JavaScript UDFs with existing infrastructure. This Couchbase blog post demonstrates just how to do that and more!","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:\/\/www.couchbase.com\/blog\/es\/recursive-query-processing-in-sql-n1ql\/","og_locale":"es_MX","og_type":"article","og_title":"Recursive Query Processing in SQL++ (N1QL)","og_description":"Users can emulate recursive CTE using JavaScript UDFs with existing infrastructure. This Couchbase blog post demonstrates just how to do that and more!","og_url":"https:\/\/www.couchbase.com\/blog\/es\/recursive-query-processing-in-sql-n1ql\/","og_site_name":"The Couchbase Blog","article_published_time":"2023-06-23T20:15:52+00:00","article_modified_time":"2024-03-01T17:01:33+00:00","og_image":[{"width":1920,"height":2560,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/06\/remy-penet-zaM9LhySx_0-unsplash-scaled.jpg","type":"image\/jpeg"}],"author":"Gaurav Jayaraj - Software Engineer","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Gaurav Jayaraj - Software Engineer","Est. reading time":"8 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/"},"author":{"name":"Gaurav Jayaraj - Software Engineer","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/546cec92f77cbb0b09f9b973fd1c8d42"},"headline":"Recursive Query Processing in SQL++ (N1QL)","datePublished":"2023-06-23T20:15:52+00:00","dateModified":"2024-03-01T17:01:33+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/"},"wordCount":1232,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/remy-penet-zaM9LhySx_0-unsplash-scaled.jpg","keywords":["recursive queries","User Defined Function (UDF)"],"articleSection":["Couchbase Server","Data Modeling","JavaScript","SQL++ \/ N1QL Query"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/","url":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/","name":"Recursive Query Processing in SQL++ (N1QL) Function","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/remy-penet-zaM9LhySx_0-unsplash-scaled.jpg","datePublished":"2023-06-23T20:15:52+00:00","dateModified":"2024-03-01T17:01:33+00:00","description":"Users can emulate recursive CTE using JavaScript UDFs with existing infrastructure. This Couchbase blog post demonstrates just how to do that and more!","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/remy-penet-zaM9LhySx_0-unsplash-scaled.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/06\/remy-penet-zaM9LhySx_0-unsplash-scaled.jpg","width":1920,"height":2560,"caption":"Fibonacci design of staircase by Remy Penet on Unsplash"},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Recursive Query Processing in SQL++ (N1QL)"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/546cec92f77cbb0b09f9b973fd1c8d42","name":"Gaurav Jayaraj - Ingeniero de software","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/a332e5d7f47865015367ca88af3e5891","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/02\/unnamed-2.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/02\/unnamed-2.jpg","caption":"Gaurav Jayaraj - Software Engineer"},"description":"Gaurav Jayaraj es becario en el equipo de consultas de Couchbase R&amp;D. Gaurav es licenciado en Inform\u00e1tica por la Universidad PES de Bangalore.","url":"https:\/\/www.couchbase.com\/blog\/es\/author\/gauravjayaraj\/"}]}},"authors":[{"term_id":9835,"user_id":84423,"is_guest":0,"slug":"gauravjayaraj","display_name":"Gaurav Jayaraj - Software Engineer","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/02\/unnamed-2.jpg","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/02\/unnamed-2.jpg"},"first_name":"Gaurav","last_name":"Jayaraj - Software Engineer","user_url":"","author_category":"","description":"Gaurav Jayaraj es becario en el equipo de consultas de Couchbase R&amp;D. Gaurav es licenciado en Inform\u00e1tica por la Universidad PES de Bangalore."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/14562","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/84423"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=14562"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/14562\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/14577"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=14562"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=14562"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=14562"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=14562"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}