{"id":9720,"date":"2021-08-25T00:00:09","date_gmt":"2021-08-25T07:00:09","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=9720"},"modified":"2025-06-13T23:34:39","modified_gmt":"2025-06-14T06:34:39","slug":"n1ql-user-defined-functions","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/n1ql-user-defined-functions\/","title":{"rendered":"N1QL ya admite funciones definidas por el usuario"},"content":{"rendered":"<p><strong>Los lenguajes de consulta declarativos han supuesto un cambio importante<\/strong> en el mundo de los motores de bases de datos.<\/p>\n<p>En <a href=\"https:\/\/www.couchbase.com\/blog\/es\/sqlplusplus\/?ref=blog\" target=\"_blank\" rel=\"noopener\">Lenguaje de consulta SQL<\/a> (antes N1QL) es principalmente un lenguaje de consulta declarativo. T\u00fa le dices a la consulta lo que quieres obtener y N1QL se encarga del resto de los detalles.<\/p>\n<p>Sin embargo, la capacidad de instruir program\u00e1ticamente su consulta a la base de datos es \u00fatil en varias situaciones. Despu\u00e9s de todo, usted conoce su propia l\u00f3gica de negocio - N1QL no.<\/p>\n<p>Entre en <em>funciones definidas por el usuario (UDF)<\/em>. Las UDF le ofrecen un mayor control sobre una consulta concreta y le permiten indicar al lenguaje de consulta c\u00f3mo se realizan determinadas tareas. <a href=\"https:\/\/www.couchbase.com\/blog\/es\/couchbase-server-7-0-release\/?ref=blog\" target=\"_blank\" rel=\"noopener\">La versi\u00f3n 7.0 de Couchbase Server<\/a> incluye funciones definidas por el usuario para el lenguaje de consulta N1QL.<\/p>\n<p>N1QL es bastante agn\u00f3stico en cuanto a lenguajes de programaci\u00f3n subyacentes. En lugar de especificar su propio lenguaje procedimental, N1QL emplea un <em>Gestor ling\u00fc\u00edstico<\/em>lo que significa que ya est\u00e1 dise\u00f1ado para admitir multitud de idiomas invitados.<\/p>\n<p>Por ahora, las lenguas admitidas son <em>en l\u00ednea<\/em>un lenguaje interno que permite codificar cualquier expresi\u00f3n N1QL v\u00e1lida (incluidas las subconsultas) y <em>JavaScript<\/em>. Comencemos comparando estos dos lenguajes soportados para las UDFs de N1QL.<\/p>\n<h2>Ejemplo de UDF N1QL: Uso b\u00e1sico<\/h2>\n<p>Para a\u00f1adir su l\u00f3gica de negocio, tiene que crear funciones, como la funci\u00f3n <em>en l\u00ednea<\/em> ejemplo siguiente:<\/p>\n<pre class=\"lang:mysql decode:true\">CREATE FUNCTION add(arg1, arg2) { arg1 + arg2 }\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>You can then use your business logic freely wherever an expression is allowed, or directly through the `EXECUTE FUNCTION` statement:<\/p>\n<pre class=\"lang:default decode:true\">select add(1, 2)\r\nEXECUTE FUNCTION add(1, 2)\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>Y cuando ya no te sirva, lo dejas:<\/p>\n<pre class=\"lang:default decode:true\">DROP FUNCTION add\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<h2>N1QL UDF Ejemplo: JavaScript<\/h2>\n<p>Crear y soltar funciones JavaScript definidas por el usuario es un poco m\u00e1s enrevesado, por razones que se har\u00e1n evidentes en la siguiente secci\u00f3n.<\/p>\n<p>Las UDF de JavaScript son t\u00e9cnicamente <em>externo<\/em> funciones. Esto se debe a que est\u00e1n escritas en un lenguaje diferente y se ejecutan en un proceso distinto al del Servicio de Consulta N1QL.<\/p>\n<p>El primer paso es crear el c\u00f3digo JavaScript:<\/p>\n<pre class=\"lang:default decode:true\">curl -v -X POST https:\/\/localhost:8093\/evaluator\/v1\/libraries\/math -u Administrador:contrase\u00f1a -d 'function add(a, b) { let data = a + b; return data; }'\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>A continuaci\u00f3n, cree la funci\u00f3n N1QL:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION javascriptAdd(a, b) LANGUAGE javascript AS \"add\" AT \"math\"\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>Una vez creada, puede crear y soltar UDFs JavaScript exactamente igual que las inline. Cuando ya no necesites la biblioteca, puedes eliminarla mediante este comando:<\/p>\n<pre class=\"lang:default decode:true\">curl -v -X DELETE https:\/\/localhost:8093\/evaluator\/v1\/libraries\/math -u Administrator:password\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<h2>Nuevo en Couchbase 7.0: Funciones definidas por el usuario para \u00e1mbitos y colecciones<\/h2>\n<p>Una de las principales caracter\u00edsticas de la versi\u00f3n 7.0 de Couchbase Server es la introducci\u00f3n de <a href=\"https:\/\/www.couchbase.com\/blog\/es\/scopes-and-collections-for-modern-multi-tenant-applications-couchbase-7-0\/?ref=blog\" target=\"_blank\" rel=\"noopener\">\u00c1mbitos y colecciones<\/a> para ayudarle a organizar su <a href=\"https:\/\/www.couchbase.com\/blog\/es\/json-database\/?ref=blog\" target=\"_blank\" rel=\"noopener\">JSON<\/a> documentos. Las colecciones son unidades de almacenamiento para un grupo de documentos similares, y los \u00e1mbitos son unidades de almacenamiento m\u00e1s grandes que contienen varias colecciones, lo que permite particionar las aplicaciones.<\/p>\n<p>Con \u00e1mbitos y colecciones, <a href=\"https:\/\/www.couchbase.com\/blog\/es\/products\/server\/?ref=blog\" target=\"_blank\" rel=\"noopener\"><br \/>\nServidor Couchbase<\/a> - una base de datos documental- ofrece ahora todos los puntos fuertes del modelo relacional -esquema, tablas, columnas- sin ninguno de sus puntos d\u00e9biles.<\/p>\n<p><em>R\u00e1pido paso lateral:<\/em> In order to allow backward compatibility, the Query Service now has a `query_context` REST API parameter that indicates which Bucket and Scope should be used to resolve relative keyspace names, for example:<\/p>\n<pre class=\"lang:default decode:true\">cbq&gt; \\set -query_context \"default:travel-sample.scope1\";\r\ncbq&gt; select * from airlines;\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>In the statement above, the `SELECT` statement resolves `airlines` to the Collection named `default:travel-sample.scope1.airlines`.<\/p>\n<p>Bien, ahora volvamos a las funciones definidas por el usuario:<\/p>\n<p>La l\u00f3gica que subyace a los \u00e1mbitos y las colecciones con UDF es que se pueden tener entornos de desarrollo, preproducci\u00f3n y producci\u00f3n de la misma aplicaci\u00f3n en tres \u00e1mbitos diferentes, en los que se despliegan tres copias de la misma aplicaci\u00f3n con la misma l\u00f3gica. A la inversa, podr\u00eda tener Scopes que contengan diferentes despliegues de la misma aplicaci\u00f3n donde se requiera una l\u00f3gica de negocio diferente (por ejemplo, tiendas online donde se apliquen diferentes estructuras de descuento o entrega, o una aplicaci\u00f3n de contabilidad, donde se apliquen diferentes reglas de impuestos).<\/p>\n<p>En el primer caso, basta con tener una definici\u00f3n global para las funciones individuales porque la l\u00f3gica empresarial es la misma. Pero para el segundo caso, las UDF deben dividirse en \u00e1mbitos. Cada \u00e1mbito puede tener su propia instancia de la misma UDF, cada una con una l\u00f3gica diferente.<\/p>\n<p>Tambi\u00e9n vale la pena se\u00f1alar que Couchbase Server 7.0 no te obliga a cambiar a \u00c1mbitos y Colecciones, por lo que era importante que las UDFs no estuvieran atadas a la caracter\u00edstica de Colecciones.<\/p>\n<h3>Nota sobre las UDF globales<\/h3>\n<p>Las UDF globales no dependen de \u00e1mbitos, lo que significa que son compatibles con las UDF introducidas en la versi\u00f3n 6.5.<\/p>\n<p>Si no utiliza Colecciones, no tiene que hacer nada especial para utilizarlas.<br \/>\nLas UDF globales se referencian utilizando un nombre completo de dos partes, como se indica a continuaci\u00f3n:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION default:bucket1.scope1.func1()  { 0 };\r\nEXECUTE FUNCTION default:bucket1.scope1.func1();\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<h3>Importancia del par\u00e1metro query_context<\/h3>\n<p>\"Vale, ahora estoy confuso\", te oigo decir. \"\u00bfQu\u00e9 funciones estabas usando entonces en los ejemplos anteriores? Los nombres no estaban completamente cualificados\".<\/p>\n<p>The answer lies in the `query_context` REST API parameter setting: if the `query_context` is unset, the N1QL parser resolves the name to <em>global<\/em> functions. If the `query_context` is set, the parser uses the `query_context` value to resolve the names to the relevant Scope functions, much like it did with non-qualified keyspace names.<\/p>\n<p>You can seamlessly deploy your application against Scopes or against Buckets just by changing the setting of the `query_context` REST API parameter.<\/p>\n<h3>Resoluci\u00f3n de objetos dentro de funciones<\/h3>\n<p>Cuando las funciones definidas por el usuario hacen referencia a objetos totalmente cualificados, no hay ambig\u00fcedad sobre a qu\u00e9 objeto se refieren:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION func { (SELECT * FROM default:bucket1.scope1.collection1) };\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>La siguiente pregunta es: \u00bfc\u00f3mo resuelven las funciones los objetos a los que hacen referencia? Por ejemplo:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION func1() { func2() };\r\nCREATE FUNCTION default:func3 { (SELECT * FROM keyspace1) };\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>La clave aqu\u00ed es el principio de menor sorpresa: durante la ejecuci\u00f3n, las funciones definidas por el usuario cambian el contexto de consulta a la ruta bajo la cual fueron creadas y siempre hacen referencia a objetos dentro de esa ruta.<\/p>\n<p>No importa si las has llamado con una ruta relativa o completa, una funci\u00f3n llamada con los mismos par\u00e1metros siempre devuelve los mismos resultados, que se toman de los mismos objetos.<\/p>\n<p>In the first example above, `func2()` would resolve to a global or a Scope function depending on the `query_context` setting at creation time.<\/p>\n<p>For `func3()`, `keyspace1` would be the Bucket `keyspace1`.<\/p>\n<h3>Combinaci\u00f3n de funciones globales y de \u00e1mbito<\/h3>\n<p>No hay nada que le impida utilizar UDF globales junto con la funci\u00f3n Colecciones: s\u00f3lo tiene que utilizar los nombres completos.<\/p>\n<p>Del mismo modo, si desea utilizar una funci\u00f3n Scope creada en un Scope diferente, basta con referenciarla directamente.<\/p>\n<h3>Las funciones de JavaScript, de nuevo<\/h3>\n<p>He aqu\u00ed por qu\u00e9 las funciones JavaScript deben dividirse en dos partes, es decir, un cuerpo y una definici\u00f3n de funci\u00f3n independiente:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Cuando se crea el cuerpo independientemente de la definici\u00f3n de la funci\u00f3n, se puede reutilizar el mismo cuerpo en varios lugares. La misma funci\u00f3n en varios lugares puede hacer referencia al mismo cuerpo, y cuando el cuerpo se edita o se redefine, el cambio se aplica autom\u00e1ticamente a todas las definiciones de funci\u00f3n relacionadas.<\/li>\n<li>Del mismo modo, este patr\u00f3n tambi\u00e9n es importante cuando se trata de soltar o eliminar funciones. Cuando necesitas eliminar una instancia de una funci\u00f3n, el cuerpo necesita permanecer en su lugar si es usado por otras instancias.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>Trucos y consejos para usar funciones definidas por el usuario N1QL en Couchbase 7.0<\/h2>\n<h3>C\u00f3mo nombrar las UDF<\/h3>\n<p>Los nombres UDF son identificadores y no pueden coincidir con nombres de funciones predefinidas. Si los nombres <em>do<\/em> tiene prioridad la funci\u00f3n predefinida, lo que significa que no se utiliza su UDF.<\/p>\n<p>Si desea utilizar un nombre de funci\u00f3n predefinido (por alg\u00fan motivo), debe calificarlo completamente cuando haga referencia a \u00e9l. Por ejemplo:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION length(arg) { 0 };\r\nSELECT default:length(type) FROM `travel-sample`;\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<h3>Par\u00e1metros UDF<\/h3>\n<p>Las funciones definidas por el usuario de N1QL admiten tres tipos de listas de par\u00e1metros:<\/p>\n<ol>\n<li>Par\u00e1metros vac\u00edos\n<pre class=\"lang:default decode:true\">CREATE FUNCTION func1() { 0 }\r\n<\/pre>\n<p>La funci\u00f3n no admite par\u00e1metros. Si se pasa alg\u00fan par\u00e1metro, se produce un error.<\/li>\n<li>Par\u00e1metros vari\u00e1dicos\n<pre class=\"lang:default decode:true\">CREATE FUNCTION func1(...) { array_length(args) }\r\n<\/pre>\n<p>Three dots denote a variadic function. It can take any number of parameters of any type. The parameters are contained in an array names `args`.<\/li>\n<li>Par\u00e1metros con nombre\n<pre class=\"lang:default decode:true\">CREATE FUNCTION func1(arg1) { arg1 }\r\n<\/pre>\n<p>Los par\u00e1metros no est\u00e1n tipados, pero se aplica el n\u00famero de argumentos pasados.<\/li>\n<\/ol>\n<h3>Algunos consejos sobre sobrecarga y manipulaci\u00f3n de tipos<\/h3>\n<p>Los par\u00e1metros no tipados y las funciones vari\u00e1dicas son lo m\u00e1s cercano que Couchbase llegar\u00e1 a la sobrecarga de funciones: donde la misma funci\u00f3n se define varias veces con una lista de par\u00e1metros diferente - o diferentes tipos de par\u00e1metros - con el fin de ser capaz de operar de manera diferente dependiendo de la entrada.<\/p>\n<p>Yo recomendar\u00eda esta estrategia N1QL en su lugar: Tener una \u00fanica funci\u00f3n que compruebe los argumentos recibidos y act\u00fae en consecuencia.<\/p>\n<p>A continuaci\u00f3n se ofrece un ejemplo de funci\u00f3n vari\u00e1dica:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION variadic(...) { CASE WHEN array_length(args) != 1 THEN \"wrong args: \" || to_string(array_length(args))  WHEN type(args[0]) = \"string\" THEN args[0] ELSE \"wrong type \" || type(args[0]) || \": \" || to_string(args[0]) END }\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>Y una funci\u00f3n no variable:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION twoargs(arg1, arg2) { CASE WHEN type(arg1) != \"string\" THEN \"wrong arg1 \" || type(arg1) || \": \" || to_string(arg1) WHEN type(arg2) != \"string\" THEN \"wrong arg2 \" || type(arg2) || \": \" || to_string(arg2) ELSE arg1 || arg2 END }\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<h3>Nombres de par\u00e1metros frente a campos de documento<\/h3>\n<p>Considera la siguiente funci\u00f3n:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION docsOfType(type) { (SELECT * from `travel-sample` WHERE type=type) }\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>\u00bfNota c\u00f3mo la funci\u00f3n declara un par\u00e1metro que resulta tener el mismo nombre que un campo de documento? Est\u00e1 claro que esa funci\u00f3n no cumple su objetivo, ya que no hay forma de distinguir entre los dos.<\/p>\n<p>Here\u2019s how you use parameters names to get around this problem: Parameter names override document fields (either way, the above query returns all documents in the `travel-sample` dataset).<\/p>\n<p>Para acceder a los campos del documento, tiene dos opciones. O bien hacer referencia al campo del documento con su nombre completo, como puede ver a continuaci\u00f3n:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION docsOfType(type) { (SELECT * from `travel-sample` WHERE travel-sample.type=type) }\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>O bien, elimine la ambig\u00fcedad cambiando el nombre del par\u00e1metro, como se indica a continuaci\u00f3n:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION docsOfType(vType) { (SELECT * from `travel-sample` WHERE type=vType) }\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<h3>Valores de retorno con UDFs<\/h3>\n<p>Las funciones definidas por el usuario s\u00f3lo devuelven un valor de cualquier tipo. Si necesita devolver m\u00e1s de un valor, devuelva una matriz o un objeto.<\/p>\n<p><strong>Pero \u00a1cuidado con los tipos de devoluci\u00f3n!<\/strong> Remember that `SELECT` statements executed inside UDFs return arrays, so even if your `SELECT` returns just one document, it is a one-element array. Instead, return the first element of the array.<\/p>\n<p>Por ejemplo, esta funci\u00f3n de abajo no hace lo que quieres:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION tsample() { (SELECT * FROM `travel-sample` LIMIT 1) }\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>Pero \u00e9ste s\u00ed:<\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION tsample1st() { (SELECT * FROM `travel-sample` LIMIT 1)[0] }\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<h3>Utilizaci\u00f3n de los valores de retorno UDF como datos para la consulta<\/h3>\n<p>En el lado opuesto del espectro, dado que las UDFs pueden devolver arrays, pueden utilizarse provechosamente para generar din\u00e1micamente datos para ser consultados, de forma muy similar a como se har\u00eda en motores Relacionales con conceptos como Funciones de Tabla o Tablas Derivadas de Colecciones, como en el siguiente ejemplo<\/p>\n<pre class=\"\">SELECT * FROM tsample() sample<\/pre>\n<p>Aunque la funci\u00f3n de ejemplo selecciona datos de un cubo, se puede utilizar cualquier forma v\u00e1lida de construir una matriz para generar los datos.<\/p>\n<h3>Cuando necesite actualizar una funci\u00f3n existente<\/h3>\n<p>Sometimes you need to redefine a function. The `OR REPLACE` clause of the `CREATE FUNCTION` statement allows you to do just that in a single step:<\/p>\n<pre class=\"lang:default decode:true\">CREATE OR REPLACE FUNCTION tsample1st() { (SELECT * FROM `travel-sample` LIMIT 1)[0] }\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<h3>Privilegios de acceso de los usuarios<\/h3>\n<p>Cualquier sentencia N1QL ejecutada dentro de una UDF se ejecuta con los mismos privilegios que el usuario que envi\u00f3 la petici\u00f3n. Por lo tanto, el usuario debe tener los privilegios adecuados para acceder a todos los objetos a los que hace referencia la UDF.<\/p>\n<p>Adem\u00e1s de todo esto, el usuario tambi\u00e9n necesita tener privilegios para ejecutar funciones. Existen distintos niveles de privilegios para las funciones internas, externas, globales y de \u00e1mbito. Para crear y soltar funciones, el usuario debe tener permiso para gestionar funciones. Por ejemplo:<\/p>\n<pre class=\"lang:default decode:true\">GRANT query_manage_global_functions TO user1;\r\nGRANT query_execute_external_functions ON default:test.scope1 TO user1;\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<h2>Conclusi\u00f3n<\/h2>\n<p>Espero que hayas encontrado este post \u00fatil para entender cu\u00e1ndo y c\u00f3mo aprovechar las funciones definidas por el usuario N1QL con Couchbase 7.0. Echa un vistazo a la documentaci\u00f3n de <a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/n1ql\/n1ql-language-reference\/userfun.html?ref=blog\" target=\"_blank\" rel=\"noopener\"> m\u00e1s informaci\u00f3n sobre las funciones definidas por el usuario<\/a>Contexto <a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/n1ql\/n1ql-intro\/sysinfo.html?ref=blog#logical-hierarchy\" target=\"_blank\" rel=\"noopener\">N1QL objects and `query_context`<\/a> y <a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/learn\/security\/roles.html?ref=blog#manage-global-functions\" target=\"_blank\" rel=\"noopener\">funciones de seguridad para las UDF<\/a>.<\/p>\n<div class=\"wp-block-spacer\" style=\"height: 30px;\" aria-hidden=\"true\"><\/div>\n<div style=\"text-align: center;\"><strong>\u00bfQuiere probar las UDF?<br \/>\n<a href=\"https:\/\/www.couchbase.com\/blog\/es\/downloads\/?ref=blog\" target=\"_blank\" rel=\"noopener\">Pruebe Couchbase 7<\/a><\/strong><\/div>\n<div class=\"wp-block-spacer\" style=\"height: 15px;\" aria-hidden=\"true\"><\/div>\n<p>&nbsp;<\/p>","protected":false},"excerpt":{"rendered":"<p>Declarative query languages have been a major gear shift in the world of database engines. The SQL++ query language (formerly N1QL) is primarily a declarative query language. You tell the query what to get and N1QL works out the rest [&hellip;]<\/p>","protected":false},"author":1782,"featured_media":11779,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1815,1816,9327,1812],"tags":[1867,2312,1543,1261,8911],"ppma_author":[8924],"class_list":["post-9720","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-couchbase-server","category-javascript","category-n1ql-query","tag-business-logic","tag-document-database","tag-javascript","tag-json","tag-udf"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.9 (Yoast SEO v25.9) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>N1QL Now Supports User-Defined Functions<\/title>\n<meta name=\"description\" content=\"Discover what\u2019s possible with the introduction of user-defined functions to the N1QL query language in Couchbase 7, including these UDF tips and tricks.\" \/>\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\/n1ql-user-defined-functions\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"N1QL Now Supports User-Defined Functions\" \/>\n<meta property=\"og:description\" content=\"Discover what\u2019s possible with the introduction of user-defined functions to the N1QL query language in Couchbase 7, including these UDF tips and tricks.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/n1ql-user-defined-functions\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-08-25T07:00:09+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T06:34:39+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0-social.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"800\" \/>\n\t<meta property=\"og:image:height\" content=\"418\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Marco Greco, Software Architect, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0-social.jpg\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Marco Greco, Software Architect, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/\"},\"author\":{\"name\":\"Marco Greco, Software Architect, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2b5184a7cdb443ff2897aff0866cd6fd\"},\"headline\":\"N1QL Now Supports User-Defined Functions\",\"datePublished\":\"2021-08-25T07:00:09+00:00\",\"dateModified\":\"2025-06-14T06:34:39+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/\"},\"wordCount\":1771,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0.jpg\",\"keywords\":[\"Business Logic\",\"document database\",\"javascript\",\"JSON\",\"User Defined Function (UDF)\"],\"articleSection\":[\"Best Practices and Tutorials\",\"Couchbase Server\",\"JavaScript\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/\",\"name\":\"N1QL Now Supports User-Defined Functions\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0.jpg\",\"datePublished\":\"2021-08-25T07:00:09+00:00\",\"dateModified\":\"2025-06-14T06:34:39+00:00\",\"description\":\"Discover what\u2019s possible with the introduction of user-defined functions to the N1QL query language in Couchbase 7, including these UDF tips and tricks.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0.jpg\",\"width\":1200,\"height\":628,\"caption\":\"Learn these tips and tricks for creating user-defined functions (UDFs) with the N1QL query language\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"N1QL Now Supports User-Defined Functions\"}]},{\"@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\/2b5184a7cdb443ff2897aff0866cd6fd\",\"name\":\"Marco Greco, Software Architect, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/707c967b795fd71b6330f6d3118cf308\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6be0ee56851d2f71a554731d5edd5c820069680f0a810b47f094091c58bc553?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6be0ee56851d2f71a554731d5edd5c820069680f0a810b47f094091c58bc553?s=96&d=mm&r=g\",\"caption\":\"Marco Greco, Software Architect, Couchbase\"},\"description\":\"In a previous life, Marco used to be CTO, radiation physicist, software architect, sysadmin, DBA, trainer and general handyman at Italy's largest radiation theraphy practice. Having switched career and country, he spent more than two decades in various support and development positions in Informix first and IBM later, before finally taking the plunge and joining Couchbase, to help them make gold out of N1QL. He holds several patents and has authored open source projects of his own.\",\"sameAs\":[\"https:\/\/github.com\/marcogrecopriolo\",\"https:\/\/www.linkedin.com\/in\/marco-greco-7665308\/\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/marcocouchbase-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"N1QL ya admite funciones definidas por el usuario","description":"Descubre lo que es posible con la introducci\u00f3n de funciones definidas por el usuario al lenguaje de consulta N1QL en Couchbase 7, incluyendo estos consejos y trucos UDF.","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\/n1ql-user-defined-functions\/","og_locale":"es_MX","og_type":"article","og_title":"N1QL Now Supports User-Defined Functions","og_description":"Discover what\u2019s possible with the introduction of user-defined functions to the N1QL query language in Couchbase 7, including these UDF tips and tricks.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/n1ql-user-defined-functions\/","og_site_name":"The Couchbase Blog","article_published_time":"2021-08-25T07:00:09+00:00","article_modified_time":"2025-06-14T06:34:39+00:00","og_image":[{"width":800,"height":418,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0-social.jpg","type":"image\/jpeg"}],"author":"Marco Greco, Software Architect, Couchbase","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0-social.jpg","twitter_misc":{"Written by":"Marco Greco, Software Architect, Couchbase","Est. reading time":"9 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/"},"author":{"name":"Marco Greco, Software Architect, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2b5184a7cdb443ff2897aff0866cd6fd"},"headline":"N1QL Now Supports User-Defined Functions","datePublished":"2021-08-25T07:00:09+00:00","dateModified":"2025-06-14T06:34:39+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/"},"wordCount":1771,"commentCount":1,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0.jpg","keywords":["Business Logic","document database","javascript","JSON","User Defined Function (UDF)"],"articleSection":["Best Practices and Tutorials","Couchbase Server","JavaScript","SQL++ \/ N1QL Query"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/","url":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/","name":"N1QL ya admite funciones definidas por el usuario","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0.jpg","datePublished":"2021-08-25T07:00:09+00:00","dateModified":"2025-06-14T06:34:39+00:00","description":"Descubre lo que es posible con la introducci\u00f3n de funciones definidas por el usuario al lenguaje de consulta N1QL en Couchbase 7, incluyendo estos consejos y trucos UDF.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/12\/user-defined-functions-n1ql-query-language-couchbase-7-0.jpg","width":1200,"height":628,"caption":"Learn these tips and tricks for creating user-defined functions (UDFs) with the N1QL query language"},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"N1QL Now Supports User-Defined Functions"}]},{"@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\/2b5184a7cdb443ff2897aff0866cd6fd","name":"Marco Greco, Arquitecto de software, Couchbase","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/707c967b795fd71b6330f6d3118cf308","url":"https:\/\/secure.gravatar.com\/avatar\/e6be0ee56851d2f71a554731d5edd5c820069680f0a810b47f094091c58bc553?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6be0ee56851d2f71a554731d5edd5c820069680f0a810b47f094091c58bc553?s=96&d=mm&r=g","caption":"Marco Greco, Software Architect, Couchbase"},"description":"En su vida anterior, Marco fue director de tecnolog\u00eda, radiof\u00edsico, arquitecto de software, administrador de sistemas, administrador de bases de datos, formador y manitas en general en la mayor cl\u00ednica de radioterapia de Italia. Tras cambiar de carrera y de pa\u00eds, pas\u00f3 m\u00e1s de dos d\u00e9cadas en varios puestos de soporte y desarrollo en Informix primero e IBM despu\u00e9s, antes de dar finalmente el paso y unirse a Couchbase, para ayudarles a convertir N1QL en oro. Es titular de varias patentes y autor de sus propios proyectos de c\u00f3digo abierto.","sameAs":["https:\/\/github.com\/marcogrecopriolo","https:\/\/www.linkedin.com\/in\/marco-greco-7665308\/"],"url":"https:\/\/www.couchbase.com\/blog\/es\/author\/marcocouchbase-com\/"}]}},"authors":[{"term_id":8924,"user_id":1782,"is_guest":0,"slug":"marcocouchbase-com","display_name":"Marco Greco, Software Architect, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/e6be0ee56851d2f71a554731d5edd5c820069680f0a810b47f094091c58bc553?s=96&d=mm&r=g","author_category":"","last_name":"Greco","first_name":"Marco","job_title":"","user_url":"","description":"En su vida anterior, Marco fue director de tecnolog\u00eda, radiof\u00edsico, arquitecto de software, administrador de sistemas, administrador de bases de datos, formador y manitas en general en la mayor cl\u00ednica de radioterapia de Italia.\r\n\r\nTras cambiar de carrera y de pa\u00eds, pas\u00f3 m\u00e1s de dos d\u00e9cadas en varios puestos de soporte y desarrollo en Informix primero e IBM despu\u00e9s, antes de finalmente dar el paso y unirse a Couchbase, para ayudarles a convertir N1QL en oro.\r\n\r\nEs titular de varias patentes y autor de sus propios proyectos de c\u00f3digo abierto."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/9720","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\/1782"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=9720"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/9720\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/11779"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=9720"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=9720"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=9720"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=9720"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}