As funções definidas pelo usuário (UDFs) são um recurso que existe na maioria dos RDBMS. Seja no Oracle PL/SQL (Linguagem procedural para SQL), no SQL Server T-SQL (Transact-SQL), no PL/pgSQL (Linguagem procedural/PostgreSQL) ou em outras variantes, todas essas linguagens têm as características gerais de fornecer uma estrutura de blocos, controle de condições, loop de iteração e tratamento de erros. Esses blocos de construção permitem o desenvolvimento de tarefas complexas, que podem ser isoladas para melhorar a manutenção e a integridade do aplicativo.
Para o Couchbase, os critérios para escolher a linguagem para SQL++ As Funções Definidas pelo Usuário são bastante claras: elas devem ser capazes de oferecer suporte a todos os recursos existentes nas implementações atuais de RDBMS ou no mesmo nível que o serviço de consulta do Couchbase e também refletir a preferência dos desenvolvedores atuais. De acordo com as pesquisas de desenvolvedores do Stack Overflow, a linguagem de programação mais usada no mundo em 2020 é JavaScript.
SQL++ UDF/JS
O Couchbase é um banco de dados de documentos que armazena nativamente seus dados no formato JSON (JavaScódigo Oobjeto Notação). Sua linguagem de consulta, SQL++ , é SQL para JSON. A linguagem JavaScript é, portanto, a maneira mais natural de acessar e manipular dados JSON.
Consulte a documentação do Couchbase para obter mais detalhes sobre o implementação completa de JavaScript no Couchbase.
O UDF JavaScript para percorrer árvores
O JavaScript é poderoso, flexível e relativamente fácil de começar a usar. Para mostrar sua versatilidade, criei um UDF em Javascript para este artigo que percorre uma estrutura de árvore, como uma estrutura organizacional.
UDF: traverseTree
O UDF executa uma pesquisa recursiva em uma coleção usando os dois conectar campos (para e de) para a recursão.
Os parâmetros são mostrados na tabela a seguir:
| # | Nome | Descrição |
| 1 | kSpace | O espaço-chave para a consulta. Pode ser uma coleção ou consulta. |
| 2 | começar com | Iniciar a pesquisa com esse valor para o connectToFld. Se estiver vazio, a pesquisa será realizada para todos os valores de connectTo |
| 3 | connectTo | O nome do campo na coleção em que o campo connectTo será usado |
| 4 | connectFrom | O nome do campo na coleção em que o campo connectFrom será usado |
| 5 | relatórioHier | O nome do campo para a matriz de hierarquia |
| 6 | logKSpace | O espaço-chave em que é gravado o registro em log opcional para UDF. Observe que esse parâmetro só pode ser executado quando executado com EXECUTE FUNCTION. |
Exemplos de hierarquia
Vamos considerar uma estrutura hierárquica organizacional como a abaixo.

O emp A coleção tem os seguintes documentos:
|
1 2 3 4 5 6 7 8 |
[ { "empid": 1, "name": "JeffC" }, { "empid": 2, "name": "SteveA", "reportsTo": "JeffC" }, { "empid": 3, "name": "AmitG", "reportsTo": "JeffC" }, { "empid": 4, "name": "BrendaM", "reportsTo": "SteveA" }, { "empid": 5, "name": "WillG", "reportsTo": "SteveA" }, { "empid": 6, "name": "PaulD", "reportsTo": "BrendaM" } ] |
|
1 |
SELECT e.* FROM traverseTree('traversal.hierarchy.emp','','name','reportsTo','ReportHierarchy','') e; |
A consulta produz os seguintes resultados:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
[ { "ReportHierarchy": [], "name": "JeffC" }, { "ReportHierarchy": [ { "level": 1,"name": "JeffC" } ], "name": "SteveA", "reportsTo": "JeffC" }, { "ReportHierarchy": [ { "level": 1,"name": "JeffC" } ], "name": "AmitG", "reportsTo": "JeffC" }, { "ReportHierarchy": [ { "level": 1,"name": "SteveA","reportsTo": "JeffC" }, { "level": 2,"name": "JeffC" } ], "name": "BrendaM", "reportsTo": "SteveA" }, { "ReportHierarchy": [ { "level": 1,"name": "SteveA","reportsTo": "JeffC" }, { "level": 2,"name": "JeffC" } ], "name": "WillG", "reportsTo": "SteveA" }, { "ReportHierarchy": [ { "level": 1,"name": "BrendaM","reportsTo": "SteveA" }, { "level": 2,"name": "SteveA", "reportsTo": "JeffC" }, { "level": 3,"name": "JeffC" } ], "name": "PaulD", "reportsTo": "BrendaM" } ] |
Criar o traverseTree função definida pelo usuário
No Couchbase SQL++, um UDF pode ser definido de várias maneiras.
UDF como uma função escalar
|
1 2 3 4 5 |
CREATE FUNCTION to_meters(...) { args[0] * 0.3048 }; SELECT airportname, ROUND(to_meters(geo.alt)) AS mamsl FROM `travel-sample`.inventory.airport LIMIT 5; |
Como uma função em linha com uma subconsulta
|
1 2 3 4 5 6 7 8 |
CREATE FUNCTION locations(vActivity) { ( SELECT id, name, address, city FROM `travel-sample`.inventory.landmark WHERE activity = vActivity) }; SELECT l.name, l.city FROM locations("eat") AS l WHERE l.city = "Gillingham"; |
Definido como uma função externa
O traverseTree O UDF usa o mecanismo de função externa. Mas, nesse caso, fornecemos a biblioteca de código externo para a função. Consulte a documentação do Couchbase para obter mais detalhes sobre Função externa.
Veja como criar uma biblioteca de funções JavaScript:
1- Criar a biblioteca de funções - Neste exemplo, usamos o Query Workbench para criar a biblioteca JavaScript.

2 - Adicionar e editar o código JavaScript

Consulte este [link] para obter o código completo da biblioteca JavaScript traverseTree.
3 - Criar a função definida pelo usuário do SQL++
|
1 2 3 |
CREATE FUNCTION traverseTree(kSpace,startWith, connectTo, connectFrom,reportHier, debugKSpace) LANGUAGE JAVASCRIPT AS "traverseTree" AT "tree"; |
Observe que você também pode criar o UDF usando o Query Workbench.

Observações importantes
O Couchbase 7.0 adicionou UDFs de SQL++ para JavaScript. Para o Couchbase 7.1, adicionamos a capacidade de executar DMLs de SQL++ no código JavaScript. Há também vários aprimoramentos na interface do usuário do Query Workbench para o gerenciamento de UDFs.
Isenção de responsabilidade - Observe que o código JavaScript fornecido neste artigo não faz parte do produto Couchase. Ele é fornecido aqui apenas para ilustrar os recursos do SQL++ UDF usando JavaScript. Os usuários são incentivados a verificar sua exatidão e a fazer modificações para atender às suas necessidades.