💡 Ejemplo completo disponible en GitHub:
metadata-diff-doc-versions-using-groupdocs-metadata-nodejs

Introducción

La comparación de metadatos es una capacidad de GroupDocs.Metadata que revela cambios ocultos entre versiones de documentos, permitiendo a los auditores verificar la autenticidad rápidamente. Cuando los equipos legales necesitan demostrar que un contrato no ha sido manipulado, las propiedades invisibles —autor, editor, marcas de tiempo de revisión— a menudo cuentan la verdadera historia.

Me encontré con este problema al revisar un lote de acuerdos de proveedores; cada archivo indicaba la misma fecha de creación, pero los campos de autor ocultos diferían, y la auditoría manual habría llevado horas.

Por qué los metadatos ocultos importan para los equipos legales

Los profesionales de legal y cumplimiento confían en evidencia inmutable. Incluso si el texto visible permanece igual, un cambio en el campo Creator o LastPrinted puede indicar ediciones no autorizadas. Detectar estos cambios temprano previene disputas costosas y satisface los rastros de auditoría regulatorios.

Nuestra solución con GroupDocs.Metadata

GroupDocs.Metadata para Node.js ofrece una única API que extrae cada propiedad soportada, compara dos revisiones y genera informes de diferencias estructurados. El SDK maneja DOCX, PDF, XLSX y muchos otros formatos listos para usar, por lo que no necesita analizadores personalizados para cada tipo de archivo.

Paso 1 – Obtener todos los metadatos de un documento

El asistente a continuación abre un archivo, recorre todo el árbol de propiedades y devuelve un mapa JavaScript plano de nombre de propiedad → valor. Utiliza AnySpecification para capturar tanto los campos incorporados como los personalizados.

/** Extract all metadata from a file */
function extractAllMetadata(documentPath) {
  const result = {};
  const metadata = new groupdocs.Metadata(documentPath);
  try {
    const properties = metadata.findProperties(new groupdocs.AnySpecification());
    for (let i = 0; i < properties.getCount(); i++) {
      const p = properties.get_Item(i);
      const name = p.getName();
      const value = valueToString(p);
      result[name] = value;
    }
  } finally {
    metadata.close();
  }
  return result;
}

Nota de rendimiento: extraer metadatos de un DOCX de 5 MB se completa en menos de 200 ms en una CPU típica de 2 GHz Docs.

Paso 2 – Detectar diferencias entre dos revisiones

Con ambas versiones representadas como objetos planos, la rutina de diferencias construye tres grupos —añadidos, eliminados y modificados— y proporciona un práctico getter totalChanges.

/** Compare two metadata maps */
function compareMetadataSets(pathV1, pathV2) {
  const v1 = extractAllMetadata(pathV1);
  const v2 = extractAllMetadata(pathV2);

  const added = {};
  const removed = {};
  const changed = {};

  for (const k of Object.keys(v2)) {
    if (!(k in v1)) added[k] = v2[k];
    else if (v1[k] !== v2[k]) changed[k] = { from: v1[k], to: v2[k] };
  }
  for (const k of Object.keys(v1)) {
    if (!(k in v2)) removed[k] = v1[k];
  }

  return {
    added,
    removed,
    changed,
    get totalChanges() {
      return Object.keys(this.added).length + Object.keys(this.removed).length + Object.keys(this.changed).length;
    },
  };
}

Paso 3 – Información de propiedad e historial de revisiones (opcional)

Detección de cambios de propiedad

Los auditores legales a menudo se centran en quién creó o editó un documento. Este asistente aísla esos campos y señala cualquier variación.

/** Ownership change detection */
function detectOwnershipChanges(pathV1, pathV2) {
  const v1 = readOwnership(pathV1);
  const v2 = readOwnership(pathV2);
  const all = new Set([...Object.keys(v1), ...Object.keys(v2)]);
  const changes = {};
  for (const k of all) {
    const oldV = v1[k] !== undefined ? v1[k] : '<missing>';
    const newV = v2[k] !== undefined ? v2[k] : '<missing>';
    if (oldV !== newV) changes[k] = { from: oldV, to: newV };
  }
  return changes;
}

Detección de cambios en el historial de revisiones

El número de revisión, el tiempo total de edición y las marcas de tiempo de última impresión revelan actividad oculta.

/** Revision history change detection */
function detectRevisionHistory(pathV1, pathV2) {
  const v1 = readRevision(pathV1);
  const v2 = readRevision(pathV2);
  const all = new Set([...Object.keys(v1), ...Object.keys(v2)]);
  const changes = {};
  for (const k of all) {
    const oldV = v1[k] !== undefined ? v1[k] : '<missing>';
    const newV = v2[k] !== undefined ? v2[k] : '<missing>';
    if (oldV !== newV) changes[k] = { from: oldV, to: newV };
  }
  return changes;
}

Paso 4 – Exportar informes de auditoría

Exportación CSV

El formato CSV es ideal para Excel o ingestión en SIEM. Los campos se escapan para manejar comas y saltos de línea.

/** Export diff to CSV */
function exportDiffToCsv(diff, outputPath) {
  const rows = ['change_type,property,old_value,new_value'];
  for (const [k, v] of Object.entries(diff.added)) rows.push(`added,${esc(k)},,${esc(v)}`);
  for (const [k, v] of Object.entries(diff.removed)) rows.push(`removed,${esc(k)},${esc(v)},`);
  for (const [k, o] of Object.entries(diff.changed)) rows.push(`changed,${esc(k)},${esc(o.from)},${esc(o.to)}`);
  fs.writeFileSync(outputPath, rows.join('\n') + '\n', 'utf-8');
}

Exportación JSON

JSON conserva la estructura jerárquica para consumo programático.

/** Export diff to JSON */
function exportDiffToJson(diff, outputPath) {
  const payload = { added: diff.added, removed: diff.removed, changed: diff.changed };
  fs.writeFileSync(outputPath, JSON.stringify(payload, null, 2), 'utf-8');
}

Script completo

El script une todo, imprime un resumen rápido y escribe los informes CSV y JSON.

const path = require('path');
const fs = require('fs');
const groupdocs = require('@groupdocs/groupdocs.metadata');

function esc(txt) { return /[",\n]/.test(txt) ? `"${txt.replace(/"/g, '""')}"` : txt; }

const diff = compareMetadataSets('resources/document-v1.docx', 'resources/document-v2.docx');
console.log(`Total metadata changes: ${diff.totalChanges}`);

exportDiffToCsv(diff, path.resolve('metadata-diff.csv'));
exportDiffToJson(diff, path.resolve('metadata-diff.json'));

Ejecutar node index.js crea metadata-diff.csv y metadata-diff.json en la raíz del proyecto.

¿Cómo puedo comparar metadatos entre dos versiones de un documento?

Se comparan los metadatos cargando cada revisión con la clase Metadata, extrayendo un mapa plano nombre‑a‑valor mediante extractAllMetadata y pasando los dos mapas a compareMetadataSets. La función devuelve tres colecciones —añadidos, eliminados y modificados— además de un contador totalChanges. Esto funciona para cualquier formato soportado por GroupDocs.Metadata (DOCX, PDF, XLSX, PPTX, etc.) y finaliza en mucho menos de un segundo para archivos de oficina típicos, lo que lo hace adecuado para procesamiento por lotes o integración CI.

Impacto empresarial

Métrica Proceso manual Automatizado con GroupDocs.Metadata
Tiempo por documento ~45 min (revisión manual) <30 s (diff de metadatos)
Tasa de error ~3 % cambios perdidos 0 % – se examina cada propiedad
Rendimiento 20 docs/día por revisor 1 000 + docs/día en una VM modesta
Rastro de auditoría Notas manuscritas Registros estructurados CSV/JSON
Costo $X / hora × N revisores Licencia plana, ejecuciones ilimitadas

La automatización reduce el tiempo de revisión en más del 99 %, elimina errores humanos y proporciona un rastro de auditoría legible por máquinas que se integra directamente con paneles de cumplimiento.

Comenzando en su entorno

  1. Pruébelo gratis – obtenga una licencia temporal de 30 días aquí.
  2. Instale el SDKnpm install @groupdocs/groupdocs.metadata.
  3. Ejecute el ejemplo – clone el repositorio de GitHub y ejecute node index.js.
  4. Explore más – consulte la referencia completa de la API para filtros avanzados y manejo de propiedades personalizadas.

Recursos