{"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\/pt\/recursive-query-processing-in-sql-n1ql\/","title":{"rendered":"Processamento de consultas recursivas em SQL++ (N1QL)"},"content":{"rendered":"<p><span style=\"font-weight: 400\">\u00c9 extremamente prov\u00e1vel que voc\u00ea tenha se deparado com problemas com <\/span><b>pesquisas hier\u00e1rquicas ou passagem de gr\u00e1ficos<\/b><span style=\"font-weight: 400\"> em seu aplicativo como um desenvolvedor que lida com casos de uso do mundo real. E, por motivos \u00f3bvios, voc\u00ea prefere resolv\u00ea-los no n\u00edvel <\/span><b>camada de banco de dados e n\u00e3o no lado do cliente<\/b><span style=\"font-weight: 400\">.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">O que s\u00e3o pesquisas hier\u00e1rquicas?<\/span><\/h2>\n<p><span style=\"font-weight: 400\">A pesquisa hier\u00e1rquica refere-se ao processo de pesquisa e recupera\u00e7\u00e3o de dados de uma estrutura hier\u00e1rquica, como um <\/span><b>ou uma rela\u00e7\u00e3o pai-filho<\/b><span style=\"font-weight: 400\">. Envolve a navega\u00e7\u00e3o pelos n\u00edveis ou camadas da hierarquia para localizar elementos de dados espec\u00edficos ou informa\u00e7\u00f5es relacionadas, por exemplo, organogramas, sistemas de arquivos e \u00e1rvores de categorias.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Os gr\u00e1ficos s\u00e3o basicamente \u00e1rvores que podem ter ciclos, portanto, al\u00e9m disso, tamb\u00e9m poder\u00edamos cobrir casos de uso como localiza\u00e7\u00e3o de caminhos etc., desde que tenhamos configura\u00e7\u00f5es adicionais para lidar com 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 um exemplo usando uma cole\u00e7\u00e3o de funcion\u00e1rios com uma estrutura hier\u00e1rquica. Os funcion\u00e1rios s\u00e3o organizados em uma rela\u00e7\u00e3o gerente-subordinado. Realizaremos opera\u00e7\u00f5es nessa hierarquia de funcion\u00e1rios usando o Couchbase e UDFs JavaScript para demonstrar a solu\u00e7\u00e3o.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Indo do <\/span><i><span style=\"font-weight: 400\">Cole\u00e7\u00e3o de funcion\u00e1rios <\/span><\/i><span style=\"font-weight: 400\">que podemos recuperar:<\/span><\/p>\n<p><span style=\"font-weight: 400\">i) n\u00edvel de funcion\u00e1rio gen\u00e9rico:<\/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) hierarquia para cada funcion\u00e1rio:<\/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\">O que este blog aborda<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Voc\u00ea realmente gosta do <\/span><b>flexibilidade<\/b><span style=\"font-weight: 400\"> de bancos de dados NoSQL, e seu modelo de dados subjacente \u00e9 <\/span><b>JSON, <\/b><span style=\"font-weight: 400\">e \u00e9 por isso que voc\u00ea escolheu o Couchbase para suas necessidades de banco de dados (\u00f3tima escolha, ali\u00e1s :-) ).<\/span><\/p>\n<p><span style=\"font-weight: 400\">Agora que voc\u00ea tem o Couchbase como banco de dados, quer resolver o problema mencionado acima. Depois de fazer algumas pesquisas no <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/pt\/sqlplusplus\/\"><span style=\"font-weight: 400\">SQL++<\/span><\/a><span style=\"font-weight: 400\"> Documentos de refer\u00eancia de idioma<\/span><span style=\"font-weight: 400\"> voc\u00ea chegou \u00e0 conclus\u00e3o de que n\u00e3o h\u00e1 <\/span><i><span style=\"font-weight: 400\">Declara\u00e7\u00e3o <\/span><\/i><span style=\"font-weight: 400\">ou <\/span><i><span style=\"font-weight: 400\">Fun\u00e7\u00e3o <\/span><\/i><span style=\"font-weight: 400\">no SQL++ para resolver nosso problema, como o <\/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 no MongoDB ou <\/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\"> em bancos de dados SQL.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Mas <\/span><b>Com a infraestrutura existente, os usu\u00e1rios podem emular o CTE recursivo usando UDFs de JavaScript. <\/b><span style=\"font-weight: 400\">As se\u00e7\u00f5es a seguir demonstrar\u00e3o como fazer isso e muito mais!<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Solu\u00e7\u00e3o para consultas recursivas<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Para implementar essa solu\u00e7\u00e3o, precisamos criar um UDF em JavaScript que utilize um algoritmo de pesquisa de amplitude em primeiro lugar para percorrer a hierarquia de funcion\u00e1rios. O UDF recebe um <\/span><b>consulta de \u00e2ncora<\/b><span style=\"font-weight: 400\">, a <\/span><b>consulta recursiva<\/b><span style=\"font-weight: 400\">e <\/span><b>op\u00e7\u00f5es de configura\u00e7\u00e3o como par\u00e2metros<\/b><span style=\"font-weight: 400\">. A consulta \u00e2ncora recupera o conjunto inicial de funcion\u00e1rios, enquanto a consulta recursiva faz refer\u00eancia aos resultados da itera\u00e7\u00e3o anterior usando o par\u00e2metro <\/span><i><span style=\"font-weight: 400\">$1<\/span><\/i><span style=\"font-weight: 400\"> par\u00e2metro. As op\u00e7\u00f5es de configura\u00e7\u00e3o permitem a personaliza\u00e7\u00e3o, incluindo crit\u00e9rios de sa\u00edda antecipada, argumentos para consultas internas, detec\u00e7\u00e3o de ciclo, modo de explica\u00e7\u00e3o para planejamento de consultas e op\u00e7\u00f5es de registro.<\/span><\/p>\n<h3>Como usar as consultas internas<\/h3>\n<p><span style=\"font-weight: 400\">A consulta de \u00e2ncora obt\u00e9m o <\/span><b>documentos de n\u00edvel raiz<\/b><span style=\"font-weight: 400\"> da cole\u00e7\u00e3o de destino.<\/span><\/p>\n<p><span style=\"font-weight: 400\">A consulta recursiva pode usar um <\/span><i><span style=\"font-weight: 400\">JUNTAR <\/span><\/i><span style=\"font-weight: 400\">com um lado como <\/span><i><span style=\"font-weight: 400\">$1<\/span><\/i><span style=\"font-weight: 400\"> e a outra como a cole\u00e7\u00e3o de destino, para explorar a rela\u00e7\u00e3o pai-filho e executar a passagem de um n\u00edvel para outro.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Em nossa fun\u00e7\u00e3o, <\/span><i><span style=\"font-weight: 400\">$1<\/span><\/i><span style=\"font-weight: 400\"> faz o que o alias do CTE faz no CTE recursivo.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Para entender melhor como usamos o SQL++ (N1QL) em UDFs JavaScript, d\u00ea uma olhada em<\/span> <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/from-n1ql-to-javascript-and-back-part-1-introduction\/\"><span style=\"font-weight: 400\">De N1QL para JavaScript e vice-versa<\/span><\/a><span style=\"font-weight: 400\">.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Agora vamos examinar o processo passo a passo. Em primeiro lugar, <\/span><b>O processamento recursivo de consultas realmente precisa ser uma fun\u00e7\u00e3o recursiva?<\/b><\/p>\n<p><span style=\"font-weight: 400\">N\u00e3o, essa seria uma m\u00e1 escolha, considerando a complexidade de tempo (a mesma funcionalidade em uma abordagem recursiva pode ser exponencial, mas linear em uma abordagem iterativa) e todos os outros problemas, como quadros, etc., que v\u00eam junto com a recurs\u00e3o. Se estiver interessado, d\u00ea uma olhada no seguinte <\/span><a href=\"https:\/\/www.baeldung.com\/cs\/convert-recursion-to-iteration\"><span style=\"font-weight: 400\">artigo<\/span><\/a><span style=\"font-weight: 400\"> sobre a convers\u00e3o de fun\u00e7\u00f5es de recurs\u00e3o de cauda em iterativas. Al\u00e9m disso, as UDFs JS t\u00eam uma predefini\u00e7\u00e3o <\/span><b>profundidade m\u00e1xima de recurs\u00e3o de 128;<\/b><span style=\"font-weight: 400\"> isso n\u00e3o \u00e9 prefer\u00edvel para o que estamos tentando fazer. <\/span><\/p>\n<p><span style=\"font-weight: 400\">Para simplificar, qualquer tarefa iterativa faz o seguinte:<\/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\">Gostar\u00edamos de reconhecer isso <\/span><a href=\"https:\/\/www.postgresql.org\/docs\/current\/queries-with.html\"><span style=\"font-weight: 400\">artigo<\/span><\/a><span style=\"font-weight: 400\"> por sua abordagem.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Pontos a ponderar<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Como podemos manter o <\/span><b>express\u00e3o de estado<\/b><span style=\"font-weight: 400\"> e pass\u00e1-lo como um par\u00e2metro para a consulta (parte recursiva aqui)?<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Usamos a capacidade do SQL++ de passar <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-intro\/queriesandresults.html#named-placeholders\"><span style=\"font-weight: 400\">par\u00e2metros de consulta din\u00e2micos<\/span><\/a><span style=\"font-weight: 400\"> e usar consultas parametrizadas para manter o valor do estado em todos os n\u00edveis.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Usamos <\/span><em>$1<\/em> na cl\u00e1usula recursiva para fazer refer\u00eancia aos resultados das itera\u00e7\u00f5es anteriores, ou seja, a express\u00e3o de estado<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong>Como podemos otimizar?<\/strong><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Prepare inicialmente as consultas \u00e2ncora e recursivas para que possamos reutilizar os planos de consulta no momento da execu\u00e7\u00e3o.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Encontre uma maneira de examinar o plano de consulta (semelhante a um <\/span><i><span style=\"font-weight: 400\">EXPLICAR<\/span><\/i><span style=\"font-weight: 400\"> ) para que possamos gerar \u00edndices apropriados para instru\u00e7\u00f5es internas (\u00e2ncoras e recursivas).<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>A vis\u00e3o geral de alto n\u00edvel da implementa\u00e7\u00e3o \u00e9 a seguinte:<\/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 usando JS UDFs\u00a0<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Essa \u00e9 uma implementa\u00e7\u00e3o muito ing\u00eanua para come\u00e7ar a funcionar. Configuramos o <em>Breadth-First-Search<\/em> estabelecendo o fluxo da ordem de acordo com a vis\u00e3o geral acima. Aqui est\u00e1 o 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\"> link:<\/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>Como adicionar a fun\u00e7\u00e3o<\/h3>\n<p><span style=\"font-weight: 400\">Aqui est\u00e1 um <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/guides\/create-javascript-library.html\"><span style=\"font-weight: 400\">link<\/span><\/a><span style=\"font-weight: 400\"> para adicionar isso a uma biblioteca JavaScript (por exemplo <\/span><em>\"mylibrary\" (minha biblioteca)<\/em><span style=\"font-weight: 400\">) em seu servi\u00e7o de consulta e um <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/guides\/create-user-defined-function.html\"><span style=\"font-weight: 400\">link<\/span><\/a><span style=\"font-weight: 400\"> para criar o UDF a partir da biblioteca adicionada.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Crie o UDF a partir da biblioteca usando o 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>Uso<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">Argumento 1: <em>\u00c2ncora<\/em> consulta, string<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\">Argumento 2: <em>Recursivo<\/em> consulta, string <\/span><span style=\"font-weight: 400\">(usa <\/span><i><span style=\"font-weight: 400\">$1 (express\u00e3o de estado)<\/span><\/i><span style=\"font-weight: 400\"> para se referir aos resultados da itera\u00e7\u00e3o anterior)<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\">Argumento 3: Configura\u00e7\u00e3o <em>op\u00e7\u00f5es<\/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 s\u00e3o <\/span><b>obrigat\u00f3rio<\/b><span style=\"font-weight: 400\">mas voc\u00ea pode passar um <\/span><i><span style=\"font-weight: 400\">objeto vazio<\/span><\/i><span style=\"font-weight: 400\">, ou seja, <\/span><i><span style=\"font-weight: 400\">{}<\/span><\/i><span style=\"font-weight: 400\"> se n\u00e3o estiver usando nenhuma op\u00e7\u00e3o de configura\u00e7\u00e3o.<\/span><\/p>\n<p><span style=\"font-weight: 400\"><br \/>\n<\/span><b>Op\u00e7\u00f5es de configura\u00e7\u00e3o<\/b><b><\/b><\/p>\n<p style=\"padding-left: 40px\"><b>Sa\u00edda antecipada<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>levelLimit<\/em>(1 a N) - Especifica o n\u00edvel em que podemos parar. A contagem de n\u00edveis come\u00e7a em <\/span><i><span style=\"font-weight: 400\">0<\/span><\/i><span style=\"font-weight: 400\"> para obter resultados de ancoragem, <\/span><i><span style=\"font-weight: 400\">1<\/span><\/i><span style=\"font-weight: 400\"> para a primeira itera\u00e7\u00e3o\/n\u00edvel, <\/span><i><span style=\"font-weight: 400\">2<\/span><\/i><span style=\"font-weight: 400\"> para o segundo, etc.<\/span><\/p>\n<p style=\"padding-left: 40px\"><b>Argumentos para a consulta interna<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>anchorArgs<\/em> - como nomeado, por exemplo,<\/span><i><span style=\"font-weight: 400\">{\"arg:1}<\/span><\/i><span style=\"font-weight: 400\"> ou argumentos posicionais, por exemplo, <\/span><i><span style=\"font-weight: 400\">[1]<\/span><\/i><span style=\"font-weight: 400\"> para usar na consulta de \u00e2ncora.<\/span><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>recursiveArgs<\/em> - S\u00f3 podem ser argumentos posicionais, e <\/span><i><span style=\"font-weight: 400\">0<\/span><\/i><span style=\"font-weight: 400\"> deve ser reservado para a express\u00e3o de estado. Por exemplo: <\/span><i><span style=\"font-weight: 400\">[0, 1] <\/span><\/i><span style=\"font-weight: 400\">- sempre define o 0\u00ba \u00edndice (<\/span><i><span style=\"font-weight: 400\">$1<\/span><\/i><span style=\"font-weight: 400\"> arg) para <\/span><i><span style=\"font-weight: 400\">0<\/span><\/i><span style=\"font-weight: 400\">para que possamos us\u00e1-lo na cl\u00e1usula recursiva como express\u00e3o de estado.<\/span><\/p>\n<p style=\"padding-left: 40px\"><b>Detec\u00e7\u00e3o de ciclo<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>cycleFields<\/em> - Matriz de nomes de campos, por exemplo, <\/span><i><span style=\"font-weight: 400\">[\"_from\", \"_to\"]<\/span><\/i><\/p>\n<p style=\"padding-left: 40px\"><b>Explicar<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\"><em>explicar<\/em> - Verificar o plano de consulta nos logs (sets <\/span><i><span style=\"font-weight: 400\">registro <\/span><\/i><span style=\"font-weight: 400\">por padr\u00e3o)<\/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> - Exibir registros que ajudam quando se deseja registrar durante o desenvolvimento<\/span><\/p>\n<p>&nbsp;<\/p>\n<h2><span style=\"font-weight: 400\">Consultas de amostra<\/span><\/h2>\n<p><span style=\"font-weight: 400\"><br \/>\n<\/span><b>1.<\/b><span style=\"font-weight: 400\"> <b>Contar n\u00fameros de 1 a N<\/b> - exemplo mais simples de uma consulta que mostra como o CTE recursivo funciona.<\/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\">Fa\u00e7a uma breve pausa para pensar em como voc\u00ea poderia fazer isso no N1QL sem a fun\u00e7\u00e3o <\/span><span style=\"font-weight: 400\">que desenvolvemos agora. Isso \u00e9 poss\u00edvel? (Ou ser\u00e1 que acabamos de fazer<\/span><b> N1QL Turing 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. Exemplo de funcion\u00e1rios<\/b> - referem-se \u00e0 cole\u00e7\u00e3o de funcion\u00e1rios que vimos anteriormente.<\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">A. Encontre o n\u00edvel organizacional de um funcion\u00e1rio<\/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 funcion\u00e1rio se reporta \u00e0 hierarquia<\/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 \u00e2ncora: <\/span><\/p>\n<pre class=\"lang:default decode:true\">SELECT e1.*, 0 as hlevel \r\nFROM `employees` e1 \r\nWHERE e1.manager_id=\" || to_str(e.employee_id)<\/pre>\n<p>Isso pode parecer muito detalhado ao adicionar um <em>ONDE<\/em> predicado da consulta externa.  W<span style=\"font-weight: 400\">e pode usar o <\/span><em>anchorArgs<\/em> op\u00e7\u00e3o<span style=\"font-weight: 400\"> para mitigar isso!<\/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>Explicar<\/strong><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">Fornecer <\/span><span style=\"font-weight: 400\">{\"explain\": true} - <\/span><span style=\"font-weight: 400\">Voc\u00ea pode ver o plano de consulta no campo de registro\u00a0<\/span><\/p>\n<p style=\"padding-left: 40px\"><strong>Sa\u00edda antecipada<\/strong><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">Conjunto <\/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\"> - se voc\u00ea quiser apenas 2 n\u00edveis de recurs\u00e3o<\/span><\/p>\n<p>&nbsp;<\/p>\n<p style=\"padding-left: 40px\"><strong>Detec\u00e7\u00e3o de 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>Sem detec\u00e7\u00e3o de ciclo <\/b><span style=\"font-weight: 400\">a consulta para encontrar a hierarquia de n\u00edvel de funcion\u00e1rio ser\u00e1 inserida em um <\/span><b>loop infinito <\/b><i><span style=\"font-weight: 400\">e travar no tempo limite da fun\u00e7\u00e3o, desperdi\u00e7ando recursos da CPU.<\/span><\/i><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\">Considerando que, quando trabalhamos com dados de gr\u00e1ficos, \u00e9 muito prov\u00e1vel que tenhamos ciclos presentes, e \u00e9 o <\/span><b>responsabilidade do chamador da fun\u00e7\u00e3o de definir a detec\u00e7\u00e3o de ciclo dos campos apropriados.<\/b><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">Aqui, o <\/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 \u00e9 suficiente para sair no 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>Obrigado por acompanhar esse t\u00f3pico desafiador. Esperamos que ele revele mais op\u00e7\u00f5es para alguns de seus desafios de consulta recursiva!<\/p>\n<h2><span style=\"font-weight: 400\">Refer\u00eancias<\/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\">Converter fun\u00e7\u00f5es recursivas em fun\u00e7\u00f5es 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\">Documentos de refer\u00eancia da linguagem 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\">Refer\u00eancia do graphLookup do MongoDB<\/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\">Refer\u00eancia de CTE recursivo Snowflake<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.couchbase.com\/blog\/pt\/from-n1ql-to-javascript-and-back-part-1-introduction\/\"><span style=\"font-weight: 400\">Blog: De N1QL para JavaScript e vice-versa - 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\">Refer\u00eancia de consulta do 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\">Documentos de consultas e resultados do 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\">Criando uma 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\">Cria\u00e7\u00e3o de fun\u00e7\u00f5es definidas pelo usu\u00e1rio (UDF) no 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\/pt\/recursive-query-processing-in-sql-n1ql\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\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\/pt\/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\":\"pt-BR\",\"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\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\":\"pt-BR\",\"@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\/pt\/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\/pt\/recursive-query-processing-in-sql-n1ql\/","og_locale":"pt_BR","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\/pt\/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":"pt-BR","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":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/recursive-query-processing-in-sql-n1ql\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@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":"Blog do Couchbase","description":"Couchbase, o banco de dados 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":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"Blog do Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@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 - Engenheiro de software","image":{"@type":"ImageObject","inLanguage":"pt-BR","@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 \u00e9 estagi\u00e1rio na equipe de consultas da Couchbase R&amp;D. Gaurav est\u00e1 cursando bacharelado em Ci\u00eancia da Computa\u00e7\u00e3o na PES University, Bangalore.","url":"https:\/\/www.couchbase.com\/blog\/pt\/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 \u00e9 estagi\u00e1rio na equipe de consultas da Couchbase R&amp;D. Gaurav est\u00e1 cursando bacharelado em Ci\u00eancia da Computa\u00e7\u00e3o na PES University, Bangalore."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/14562","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/84423"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=14562"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/14562\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/14577"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=14562"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=14562"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=14562"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=14562"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}