🧠 Cómo extraer metadatos de tus Data Extensions en SFMC desde una CloudPage

¿Necesitas saber qué campos tiene una Data Extension, su tipo, longitud, y si son llaves primarias?

Este script en una CloudPage te permite ingresar el nombre de una DE o el ID de una carpeta y obtener toda esa información, incluyendo el número de filas que contiene cada una.

Ideal para auditar tu Business Unit o documentar tus estructuras de datos en Salesforce Marketing Cloud (SFMC).


🧪 ¿Qué hace este script?

  1. Te permite seleccionar si quieres buscar por nombre de Data Extension o por carpeta (CategoryID).
  2. Recupera todas las DEs asociadas.
  3. Extrae los metadatos de cada campo: nombre, tipo, longitud, si es llave primaria y si acepta valores nulos.
  4. También recupera el número de filas de cada DE.
  5. Muestra todo en una tabla HTML descargable como CSV.

🧩 Código completo (AMPscript + SSJS + HTML)

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Extraer metadatos de campos de DE</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 20px; }
    h1 { color: #003366; }
    form { margin-bottom: 30px; padding: 20px; border: 1px solid #ccc; width: 400px; }
    label, input, select, button { display: block; margin-top: 10px; width: 100%; }
    table { border-collapse: collapse; width: 100%; margin-top: 30px; }
    th, td { border: 1px solid #ccc; padding: 8px; text-align: left; }
    th { background-color: #f2f2f2; }
    .download-button { margin-top: 20px; }
  </style>
</head>
<body>
  <h1>Extraer metadatos de campos de DE</h1>

  <form method="GET">
    <label><strong>Destino:</strong></label>
    <label><input type="radio" name="target" value="de" %%[IF RequestParameter("target") == "de" THEN]%%checked%%[ENDIF]%%> Data Extension (nombre de la DE)</label>
    <label><input type="radio" name="target" value="folder" %%[IF RequestParameter("target") == "folder" OR EMPTY(RequestParameter("target")) THEN]%%checked%%[ENDIF]%%> Carpeta (Category ID)</label>

    <label for="identifier"><strong>Identificador:</strong></label>
    <input type="text" name="identifier" id="identifier" value="%%=v(RequestParameter("identifier"))=%%" required>

    <button type="submit">Procesar</button>
  </form>

  <script runat="server">
    Platform.Load("Core", "1.1");

    var target = Request.GetQueryStringParameter("target") || "folder";
    var identifier = Request.GetQueryStringParameter("identifier");

    if (identifier) {
      var des = [];

      // Buscar por carpeta o por nombre de DE
      if (target === "folder") {
        des = DataExtension.Retrieve({
          Property: "CategoryID",
          SimpleOperator: "equals",
          Value: parseInt(identifier)
        });
      } else {
        des = DataExtension.Retrieve({
          Property: "Name",
          SimpleOperator: "equals",
          Value: identifier
        });
      }

      if (des && des.length > 0) {
        Write('<button class="download-button" onclick="downloadTableAsCSV()">Descargar CSV</button>');
        Write("<table id='deTable'><tr><th>Nombre DE</th><th>Customer Key</th><th>Campo</th><th>Tipo</th><th>Longitud</th><th>Llave Primaria</th><th>Nullable</th><th># Filas</th></tr>");

        for (var i = 0; i < des.length; i++) {
          var de = des[i];
          var deName = de.Name;
          var deKey = de.CustomerKey;

          Platform.Variable.SetValue("@deName", deName);
  </script>

  %%[
    SET @rowCount = DataExtensionRowCount(@deName)
  ]%%

  <script runat="server">
          var rowCount = Variable.GetValue("@rowCount");
          if (!rowCount || rowCount === "") {
            rowCount = "No disponible";
          }

          try {
            var myDE = DataExtension.Init(deKey);
            var fields = myDE.Fields.Retrieve();

            if (fields && fields.length > 0) {
              for (var j = 0; j < fields.length; j++) {
                var f = fields[j];
                Write("<tr>" +
                  "<td>" + deName + "</td>" +
                  "<td>" + deKey + "</td>" +
                  "<td>" + f.Name + "</td>" +
                  "<td>" + f.FieldType + "</td>" +
                  "<td>" + (f.MaxLength || "") + "</td>" +
                  "<td>" + (f.IsPrimaryKey === true ? "Sí" : "") + "</td>" +
                  "<td>" + (f.IsNullable === true ? "Sí" : "No") + "</td>" +
                  "<td>" + rowCount + "</td>" +
                  "</tr>");
              }
            } else {
              Write("<tr><td colspan='8'><em>No se encontraron campos para la DE: " + deName + "</em></td></tr>");
            }
          } catch (e) {
            Write("<tr><td colspan='8' style='color:red;'>Error al obtener campos para la DE: " + deName + " - " + String(e) + "</td></tr>");
          }
        }
        Write("</table>");
      } else {
        Write("<p style='color:red;'>No se encontraron Data Extensions para el identificador proporcionado.</p>");
      }
    }
  </script>

  <script>
    function downloadTableAsCSV() {
      var table = document.getElementById("deTable");
      var rows = table.querySelectorAll("tr");
      let csvContent = "";
      rows.forEach(row => {
        let cols = row.querySelectorAll("td, th");
        let line = Array.from(cols).map(col => '"' + col.innerText.replace(/"/g, '""') + '"').join(",");
        csvContent += line + "\n";
      });
      var blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
      var link = document.createElement("a");
      link.href = URL.createObjectURL(blob);
      link.download = "de_metadata_export.csv";
      link.click();
    }
  </script>
</body>
</html>

recuerda que este y otros snippets de sfmc están disponibles en el repo de nuestra comunidad: https://github.com/jcgalindof/salesforce-cancun

✅ Recomendaciones

  • Puedes guardar esta CloudPage como recurso privado en tu entorno de desarrollo de SFMC.
  • Asegúrate de tener los permisos adecuados para usar DataExtension.Retrieve() y Init() en la BU.
  • Úsalo para auditorías técnicas, limpieza de datos o documentación de estructuras complejas.
  • Funciona mejor con carpetas pequeñas (menos de 100 DEs) para evitar timeouts de script.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top