Hechicería Cotlang: filtros y funciones para hechizos más poderosos (parte 2)
Si lograste llegar hasta aquí sin que tu $VALUE#answer|data te convierta en una rana o sin inundar de correos a las Artes Oscuras ([email protected]) con gritos de auxilio desesperados, felicitaciones: ya no eres un muggle de Cotlang y estás lista para la magia avanzada.
En la primera parte dominaste el Wingardium Leviosa de este lenguaje. Pero hoy aprenderás hechizos más poderosos que me fueron enseñados bajo la tutela del mismísimo Brujo Calvo en persona. Solo que esta vez, espero sean practicados en un ambiente de staging.
Si aún sientes dificultad al utilizar un $VALUE#answer|data o necesitas practicar nuevamente los hechizos básicos, te invito a repasar la parte 1:

Capítulo 1: Tu nuevo contexto
Supongamos como contexto el siguiente formulario, el cuál está diseñado para que equipos de logística y almacén registren y actualicen información crítica sobre productos electrónicos en stock.
{
"answer": {
"_id": "7890123c5c77b31459033e70",
"data": [
{
"question": "7890123c5c77b31459033e71",
"contentType": "application/vnd.cotalker.survey+text",
"identifier": "title_inventory_update",
"display": ["# Actualización de Inventario - Productos Electrónicos"],
"responses": [],
"process": []
},
{
"question": "7890123c5c77b31459033e72",
"contentType": "application/vnd.cotalker.survey+textinput",
"identifier": "operator_name",
"display": ["Nombre del operador"],
"responses": ["{\"_id\":\"78901262f5af107b02ec0817\",\"accessRoles\":[\"7890126a5088d08806bd9b10\"],\"email\":\"[email protected]\",\"job\":\"7890126b5088d08806bd9b11\",\"jobTitle\":\"Supervisora de Inventario\",\"name\":{\"secondLastName\":\"Pricila\",\"lastName\":\"Badilla\",\"names\":\"Pricila Badilla\",\"displayName\":\"Pricila Badilla\"},\"role\":\"user\",\"permissionsV2\":[\"inventory-modify\",\"reports-generate\"]}"],
"process": ["78901262f5af107b02ec0817"]
},
{
"question": "7890123c5c77b31459033e73",
"contentType": "application/vnd.cotalker.survey+number",
"identifier": "total_items",
"display": ["Total de productos a registrar"],
"responses": [15],
"process": [15]
},
{
"question": "7890123c5c77b31459033e74",
"contentType": "application/vnd.cotalker.survey+property",
"identifier": "product_list",
"display": ["Lista de productos"],
"responses": ["{\"_id\":\"682ec8550ecabad970088e70\",\"company\":\"6390a2268277602c17845656\",\"propertyType\":\"lista_de_productos\",\"subproperty\":[],\"name\":{\"code\":\"laptop_x\",\"display\":\"Laptop X\"},\"isActive\":true,\"schemaInstance\":{\"sku\":\"P1001\",\"price\":1200,\"nombre\":\"Laptop X\",\"categoria\":\"computers\",\"stock\":3},\"createdAt\":\"2025-05-22T06:46:45.460Z\",\"modifiedAt\":\"2025-05-22T06:47:47.358Z\",\"extra\":{}}","{\"_id\":\"682ec870bb0d140e8d0379c7\",\"company\":\"6390a2268277602c17845656\",\"propertyType\":\"lista_de_productos\",\"subproperty\":[],\"name\":{\"code\":\"smartphone_y\",\"display\":\"Smartphone Y\"},\"isActive\":true,\"schemaInstance\":{\"sku\":\"P2002\",\"price\":800,\"nombre\":\"Smartphone Y\",\"categoria\":\"phones\",\"stock\":10},\"createdAt\":\"2025-05-22T06:47:12.703Z\",\"modifiedAt\":\"2025-05-22T06:47:58.460Z\",\"extra\":{}}"],
"process": ["682ec8550ecabad970088e70","682ec870bb0d140e8d0379c7"]
},
{
"question": "7890123c5c77b31459033e75",
"contentType": "application/vnd.cotalker.survey+property",
"identifier": "priority",
"display": ["Prioridad de actualización"],
"responses": ["{\"_id\":\"682ec8b70ecabad970089508\",\"company\":\"6390a2268277602c17845656\",\"propertyType\":\"prioridad_actualizacion\",\"subproperty\":[],\"name\":{\"code\":\"high\",\"display\":\"High\"},\"isActive\":true,\"createdAt\":\"2025-05-22T06:48:23.793Z\",\"modifiedAt\":\"2025-05-22T06:48:23.808Z\"}"],
"process": ["682ec8b70ecabad970089508"]
},
{
"question": "682ec9b90ecabad97008a466",
"contentType": "application/vnd.cotalker.survey+textnumber",
"identifier": "peso_total_estimado_kg",
"display": ["Peso total estimado (kg)"],
"responses": ["10.5"],
"process": ["10.5"]
},
{
"question": "7890123c5c77b31459033e76",
"contentType": "application/vnd.cotalker.survey+textinput",
"identifier": "etiquetas_de_categorizacion",
"display": ["Etiquetas de categorización"],
"responses": ["__ON__","__ON__","__ON__","__OFF__"],
"process": ["electronico","alta_gama","importado"]
}
],
"uuid": "7890124e9d7024fc8624c8b7",
"company": "7890125ef618ab89d55940d8",
"user": "78901262f5af107b02ec0817",
"createdAt": "2025-05-22T08:30:00.000Z",
"startDate": "2025-05-22T08:30:00.000Z",
"modifiedAt": "2025-05-22T08:35:00.000Z"
},
"task": {
"_id": "682f6d7f0ecabad9700d46d7",
"extensions": {
"asset_inventario": {
"registro_historico": ["Pricila Badilla -- 22/05/2024", "Tamara Angulo -- 22/12/2024"]
}
}
},
"meta": {
"taskGroup": "7890126c5088d08806bd9b0f"
}
}Recuerda que si usáramos javascript, almacenaríamos este objeto en una variable (const value = {...}) y utilizaríamos las funciones de arreglos; pero con cotlang simplemente utilizamos: $VALUE.
Capítulo 2: Los nuevos hechizos de Cotlang
2.1 Casteo de números: Necesito saber cuál es el valor del peso como número entero, ya que por temas de gestión interna, la empresa necesita calcular pallets completos.
[cast=>]es una función de Cotlang que te permite convertir un tipo de dato en otro. Es útil cuando los sistemas requieren formatos específicos.- En Javascript:
return parseInt(
value.answer.data.find(
question => question.identifier === "peso_total_estimado_kg"
).process[0]
);
- En Cotlang:
$VALUE#answer|data|[find=>identifier=peso_total_estimado_kg]|process|0|[cast=>parseInt] - Resultado:
10
Explicación:
[cast=>parseInt]: "Dame solo el valor entero del número que te estoy pasando".
2.2 Transformando valores a string: El cliente necesita que el valor de total_items se envíe a su sistema SAP, el cuál solo admite valores string. Para esto debemos transformar el valor numérico a un texto.
[toString=>*]es una función de Cotlang que te permite convertir cualquier tipo de dato en texto plano.- En Javascript:
return String(
value.answer.data.find(question => question.identifier === "total_items")
.responses[0]
);- En Cotlang:
$VALUE#answer|data|[find=>identifier=total_items]|responses|0|[toString=>*] - Resultado:
"15"
Explicación:
[toString=>*]: "Convierte el valor que te entregué a un texto plano".
2.3 Extrayendo información de una lista: Necesito generar un reporte en el inventario, y para eso el sistema necesita solo los ids de los productos que el usuario seleccionó.
[map=>]es una función de Cotlang nos permite extraer un dato específico de una lista.- En Javascript:
return value.answer.data
.find(question => question.identifier === "product_list")
.responses.map(JSON.parse)
.map(register => register._id);- En Cotlang:
$VALUE#answer|data|[find=>identifier=product_list]|responses|[json=>parse]|[map=>_id] - Resultado:
[ "682ec8550ecabad970088e70", "682ec870bb0d140e8d0379c7"]
Explicación:
[json=>parse]: "Convierte este string en un objeto JSON".[map=>_id]: "Cotlang, dame solo los valores_idde esta lista de elementos."
2.4 Filtrando datos: Ahora necesito saber exclusivamente cuáles son los productos que el usuario seleccionó que tengan la categoría computers.
[filter=>]es una función de Cotlang que nos permite filtrar una lista de objetos y devuelve solo los que cumplen una condición específica.- En Javascript:
return value.answer.data
.find(question => question.identifier === "product_list")
.responses.map(JSON.parse)
.map(register => register.schemaInstance)
.filter(register => register.categoria === "computers"); $VALUE#answer|data|[find=>identifier=product_list]|responses|[json=>parse]|[map=>schemaInstance]|[filter=>categoria=computers]
Resultado: [{"sku": "P1001", "price": 1200, "nombre": "Laptop X", "categoria": "computers", "stock": 3}]
Explicación:
[json=>parse]: "Convierte este string en un objeto JSON".[map=>schemaInstance]: "Extrae solo los valoresschemaInstancede cada uno de los elementos".[filter=>categoria=computers]: "Cotlang, dame únicamente los productos electrónicos que pertenecen a la categoríacomputersde tu inventario".
2.5 Ajustando el peso: Si bien aproximamos el peso a un valor entero, el cliente dice que siempre debemos sumar 2kg al peso registrado con el usuario para evitar el error de medición.
[math=>]es una función de Cotlang que nos permite realizar operaciones matemáticas a valores numéricos.- En Javascript:
return (
parseInt(
value.answer.data.find(
question => question.identifier === "peso_total_estimado_kg"
).process[0]
) + 2
);- En Cotlang:
$VALUE#answer|data|[find=>identifier=peso_total_estimado_kg]|process|0|[cast=>parseInt]|[math=>add=2] - Resultado:
12
Explicación:
[math=>add=2]: "Cotlang, toma el valor numérico que te entregué y súmale dos unidades".
2.6 Alertando stock crítico: Al cliente le interesa mucho saber si sus productos tienen stock críticos. Para esto, todos los productos deben tener un stock mínimo de 5 unidades.
[every=>]es una función de Cotlang que verifica si todos los elementos de un array cumplen una condición. Retorna true solo si cada uno pasa el filtro.- En Javascript:
return value.answer.data
.find(question => question.identifier === "product_list")
.responses.map(JSON.parse)
.map(register => register.schemaInstance.stock)
.every(unit => unit <= 5);- En Cotlang:
$VALUE#answer|data|[find=>identifier=product_list]|responses|[json=>parse]|[map=>schemaInstance]|[map=>stock]|[every=>gt=5] - Resultado:
false
Explicación:
[map=>stock]: "De la lista que te envié, extrae solo el valor de stock".[every=>gt=5]: "Cotlang, de todos los valores que hay en esta lista, quiero que me digas si todos los elementos poseen un valor mayor a 5".
2.7 Validando permisos: Si el usuario que responde el formulario tiene el permiso reports-generate entonces Cotalker debe generar un reporte en pdf automáticamente.
[some=>]es una función de Cotlang que verifica si al menos un elemento de un array cumple una condición. Retorna true si uno o más pasan el filtro.- En Javascript:
return JSON.parse(
value.answer.data.find(question => question.identifier === "operator_name")
.responses[0]
).permissionsV2.some(permission => permission === "reports-generate");- En Cotlang:
$VALUE#answer|data|[find=>identifier=operator_name]|responses|0|[json=>parse]|permissionsV2|[some=>eq=reports-generate] - Resultado:
true
Explicación:
[some=>eq=reports-generate]: "Cotlang, de la lista que te di, busca si alguno de esos valores es igual areports-generate".
2.8 Añadiendo etiquetas no repetibles: Se acercan los "Cyber-days" y el equipo de marketing necesita trazabilidad para saber qué productos tendrán descuentos. Para esto, todos los productos registrados en esta fecha deben tener la etiqueta oferta-cyber, sin importar si el usuario la seleccionó o no en el formulario.
[add=>] es una función de Cotlag que añade un elemento a un array solo si no existe previamente. Ideal para evitar duplicados en listas de valores únicos (como etiquetas o permisos).- En Javascript:
const etiquetas = value.answer.data.find(question => question.identifier === "etiquetas_de_categorizacion").process
if (!etiquetas.includes("oferta_cyber")) etiquetas.push("oferta_cyber");
return etiquetas- En Cotlang:
$VALUE#answer|data|[find=>identifier=etiquetas_de_categorizacion]|process|[add=>string=oferta_cyber] - Resultado:
["electronico", "alta_gama", "importado", "oferta_cyber"]
Explicación:
[add=>string=oferta_cyber]: "De la lista que te di, quiero que añadas un string con el nombreoferta_cyber, si la etiqueta no existe, añádelo; pero si ya existe, no hagas nada".
2.9 Registro histórico con repeticiones: El sistema debe almacenar cada envío del usuario (nombre + fecha) en un log contenido en el asset, permitiendo valores duplicados para casos como actualizaciones múltiples en un mismo día.
[push=>] es una función de Cotlag que añade un elemento a un array siempre, aunque ya exista. Usado cuando se necesitan registros históricos o valores repetidos (como logs de cambios).- En Javascript:
const date = new Date(value.answer.createdAt);
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = date.getFullYear();
const formatedDate = `${year}-${month}-${day}`;
const user = JSON.parse(value.answer.data.find(question=>question.identifier === "operator_name")).responses[0]
const displayName = user.name.displayName
const log = `${displayName} -- ${formatDate}`
const historico = value.task.extensions.asset_inventario.registro_historico
historico.push(log)
return historico
- En Cotlang:
$VALUE#task|extensions|asset_inventario|registro_historico|[push=>string=($JOIN# – #($VALUE#answer|data|[find=>identifier=operator_name]|responses|0|[json=>parse]|name|displayName)#($VALUE#answer|createdAt|[date=>format=YYYY/MM/DD]))]
Resultado: ["Pricila Badilla – 22/05/2024", "Tamara Angulo – 22/12/2024", "Pricila Badilla – 2025/05/23"]
Explicación:
$VALUE#answer|data|[find=>identifier=operator_name]|responses|0|[json=>parse]|name|displayName: "Cotlang, dame el nombre de la persona que está respondiendo el formulario".$VALUE#answer|createdAt|[date=>format=YYYY/MM/DD]: "Dame la fecha en la que el usuario envió el formulario".$JOIN# – #($VALUE#answer|data|[find=>identifier=operator_name]|responses|0|[json=>parse]|name|displayName)#($VALUE#answer|createdAt|[date=>format=YYYY/MM/DD])): "Necesito que unas el nombre con la fecha, y que exista un--entre medio".$VALUE#task|extensions|asset_inventario|registro_historico|[push=>string=...: "Quiero que tomes el valor actual de registro histórico y añadas el nuevo texto que he creado sin importar si ya existe algún elemento igual".
Capítulo 3: El camino del Archimago
Si llegaste hasta aquí sin que tu $VALUE#log_errores explotara como una poción de Snape, felicitaciones: ya dominas la varita (sintaxis) y los hechizos (funciones). Pero el camino para destruir el último Horrocrux y convertirte en Archimago de Cotlang recién comienza.
3.1 Más allá de formularios: Cotlang no vive solo en formularios. Este lenguaje es el alma secreta de Cotalker, capaz de dar vida a bots inteligentes, automatizaciones en los flujos y hasta llamadas de red. El poder está en tus manos: Ya no solo automatizarás formularios, podrás orquestar flujos completos.
3.2 El cielo es el límite: Cotlang es tan poderoso en Cotalker, que podrás crear bots que aprueben solicitudes si cumplen múltiples reglas de negocio, sincronizar los datos de Cotalker con tus sistemas internos como SAP o algún otro CRM, o incluso generar documentos PDF que podrán ser enviados por correo.
3.3 El viaje recién empieza: Es tu turno de lanzar hechizos más grandes. Explora la documentación, experimenta en staging y sobre todo atrévete a automatizar esos procesos que todos creen "imposibles".
Las varitas eligen a los magos, pero los sistemas automatizados los construyen magos persistentes. ¿Qué crearás hoy con tu $VALUE#conocimiento recién adquirido?
Referencias:





Member discussion