┌──────────────────────────────────────────────────────────────────────────────────────────┐ │ FLUJOS_APP.js /api/data │ └──────────────────────────────────────────────────────────────────────────────────────────┘ ▲ ▲ │ │ │ │ HTTP GET MongoDB /api/data?tema=… Collections │ ┌─────────────┐ │ │ noticias │ │ ├─────────────┤ │ │ wikipedia │ │ ├─────────────┤ │ │ torrents │ │ ├─────────────┤ │ │ comparaciones│ │ └─────────────┘ │ │ │ │ ▼ ▼ ┌───────────────────────────────┐ ┌────────────────────────────────┐ │ 1) Construcción de nodesQuery │ │ 3) Construcción de linksQuery │ ├───────────────────────────────┤ ├────────────────────────────────┤ │ let nodesQuery = { │ │ let linksQuery = { │ │ tema: , │ │ porcentaje_similitud: { │ │ ...(subtematica?) │──┐ │ $gte: │ │ ...(palabraClave?) │ │ │ }, │ │ ...(fechaInicio/fechaFin?) │ │ │ noticia1: { $in: nodeIds }, │ │ } │ │ │ noticia2: { $in: nodeIds } │ └───────────────────────────────┘ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────────────────┐ │ 2) Búsqueda de nodos (Promise.all) │ ├──────────────────────────────────────────────────────────────────────────────────────────┤ │ const [wN, nN, tN] = await Promise.all([ │ │ wikipedia.find(nodesQuery).limit(nodosLimit), // → hasta N wikis │ │ noticias.find(nodesQuery).limit(nodosLimit), // → hasta N noticias │ │ torrents.find(nodesQuery).limit(nodosLimit) // → hasta N torrents │ │ ]); │ │ │ │ // Formateo a “Graph Nodes”: │ │ formattedNodes = [...wN, ...nN, ...tN].map(doc ⇒ ({ │ │ id: doc.archivo.trim(), // identificador único │ │ group: doc.subtema || 'sinSub', // color/agrupación visual │ │ tema: doc.tema, // metadato │ │ content: doc.texto, // para mostrar al hacer clic │ │ fecha: doc.fecha // filtrado por fecha │ │ })); │ └──────────────────────────────────────────────────────────────────────────────────────────┘ │ │ // Extraer lista de IDs de nodos │ nodeIds = formattedNodes.map(n ⇒ n.id) │ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────────────────┐ │ 4) Búsqueda de enlaces (comparaciones.find) │ ├──────────────────────────────────────────────────────────────────────────────────────────┤ │ const links = await comparaciones.find(linksQuery).toArray(); │ │ │ │ // linksQuery: │ │ // { porcentaje_similitud: {$gte:Min}, noticia1:{$in:nodeIds}, noticia2:{$in:nodeIds} } │ │ │ │ // Formateo a “Graph Links”: │ │ formattedLinks = links.map(l ⇒ ({ │ │ source: l.noticia1.trim(), // coincide con node.id │ │ target: l.noticia2.trim(), // idem │ │ value: l.porcentaje_similitud // grosor de la arista │ │ })); │ └──────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────────────────┐ │ 5) Respuesta al cliente │ ├──────────────────────────────────────────────────────────────────────────────────────────┤ │ res.json({ │ │ nodes: formattedNodes, // array de {id, group, tema, content, fecha} │ │ links: formattedLinks // array de {source, target, value} │ │ }); │ └──────────────────────────────────────────────────────────────────────────────────────────┘ ▲ │ │ │ fetch('/api/data?...') │ ▼ ┌──────────────────────────────────────────────────────────────────────────────────────────┐ │ output_glob_war_prueba.js │ ├──────────────────────────────────────────────────────────────────────────────────────────┤ │ • Inicializa ForceGraph3D (contenedor DOM) │ │ • getData(paramsObj) │ │ └─ construye URL: '/api/data?tema=guerra%20global&...' │ │ └─ fetch → recibe {nodes,links} │ │ └─ filtra enlaces erróneos (source/target no existentes) │ │ • graph.graphData(data) // renderiza nodos + enlaces │ │ • UI: onNodeClick → showNodeContent(), sidebar form → re-getData() │ └──────────────────────────────────────────────────────────────────────────────────────────┘