Taller fundamental 2 — Neo4j: un nodo, propiedades, una relación

Práctica guiada14 min
Duración
25 min
Módulo
1/7
Requisitos previos
el laboratorio está corriendo (etat muestra nœuds : 872), Neo4j Browser abierto y conectado
Vas a construir
dos nodos propios, Alice y Bob, unidos por una flecha, luego conectados al grafo real del curso, antes de borrar todo correctamente
Entregable
la tabla del paso 8 (Alice, sus dos relaciones, sus destinos)

Cómo leer esta página. Diez pasos, una consulta a la vez. Para cada uno: la consulta a escribir, lo que muestra Neo4j Browser, y qué mirar. Escribe tú mismo cada consulta. Los bloques «Para entender bien» son opcionales. Si el laboratorio no está iniciado o si etat no dice nœuds : 872, vuelve a la práctica guiada, sección En resumen (kit: https://github.com/hrhouma2/aiopsatlas-recherche-graphes-labo-fr).

Objetivo

En la práctica guiada, contaste 872 nodos y 3712 relaciones cargados por un script, y miraste burbujas y flechas que otra persona había dibujado. Aquí, dibujas las tuyas. Primero un nodo vacío, para ver que un nodo es exactamente eso; luego le das un nombre, una edad, una ciudad; luego un segundo nodo, y una flecha entre ambos; luego una flecha hacia un curso del conjunto de datos real. Al final, el contador de etat sube a 874, y lo devuelves a 872 eliminando lo que creaste, con el error que hay que haber visto una vez para entender qué es una relación.

El vocabulario en una imagen

Un nodo es una burbuja. Una etiqueta dice de qué tipo de burbuja se trata (Personne, Cours, Ville): es el equivalente del nombre de la tabla. Una propiedad es un valor escrito en la burbuja (nom: "Alice", age: 30): una columna. Una relación es una flecha entre dos burbujas; tiene un tipo en mayúsculas (CONNAIT, AIME), un sentido, y puede llevar sus propias propiedades. En SQL, la flecha sería una clave foránea o una tabla de unión; aquí es un objeto de pleno derecho, que creas, lees y eliminas como un nodo.

Neo4jBase SQL clásicaEn esta práctica
nodofilaAlice, Bob
etiquetatablaPersonne
propiedadcolumnanom, age, ville
relaciónclave foránea / tabla de uniónCONNAIT, AIME
tipo de relaciónnombre de la tabla de uniónCONNAIT
propiedad de relacióncolumna de la tabla de unióndepuis: 2024

Dos reglas de escritura Cypher para recordar: una burbuja se escribe entre paréntesis (p:Personne), una flecha entre corchetes con un guion y una punta -[:CONNAIT]->. La letra antes de los dos puntos (p, a, r) es un nombre temporal que eliges para reutilizar el objeto en la misma consulta.

Dónde escribir, y cómo leer la respuesta

Abre http://localhost:7474, conéctate (neo4j / aiopsatlas2026, URL localhost:7687). El editor es la línea neo4j$ en la parte superior. Envías con Ctrl + Enter (Cmd + Enter en macOS) o el botón ▶ a la derecha. Cada consulta abre un recuadro bajo el editor, el más reciente arriba.

Un recuadro muestra dos cosas. Arriba, una línea verde de balance: Created 1 node, added 1 label, Set 1 property, Deleted 2 nodes… Es la que te dice qué cambió la consulta. Debajo, si la consulta tiene un RETURN, el resultado en tres vistas: Graph (las burbujas y las flechas), Table (los valores en columnas), Raw (el JSON en bruto). Una consulta sin RETURN solo muestra el balance y Completed after … ms.

Paso 1 — Crear un nodo, solo una etiqueta

cypher
CREATE (p:Personne) RETURN p

Qué pide la consulta: crea una burbuja con la etiqueta Personne, llámala p durante la consulta, y muéstramela.

Balance: Created 1 node, added 1 label, luego Started streaming 1 record after 1 ms and completed after 2 ms.

A observar: vista Graph, una sola burbuja, y a la derecha en Results overview: Nodes (1) con la pastilla Personne (1). Haz clic en la burbuja: el panel no lista ninguna propiedad. Es un nodo mínimo: una etiqueta, nada más. Equivalente SQL: INSERT INTO personne DEFAULT VALUES, en una tabla que no tendría ninguna columna.

Para entender bien
  • Aún más mínimo, CREATE (n) sin etiqueta, también funciona. Neo4j lo acepta, pero ya no podrías encontrarla salvo recorriendo todas las burbujas del grafo: una fila sin tabla. No lo hagas; una etiqueta, siempre.
  • Personne es una etiqueta nueva en este grafo, que solo conocía cinco (Competence, Cours, Etudiant, Professeur, Ville). No tuviste que declarar nada: la primera burbuja que lleva una etiqueta la crea. Como el mapping de Elasticsearch, en el taller fundamental 1.
  • RETURN p no es obligatorio. Sin él, la consulta crea la burbuja y solo muestra el balance. Está ahí para que la veas.

Paso 2 — Darle un valor

cypher
MATCH (p:Personne) SET p.nom = 'Alice' RETURN p

Qué pide la consulta: encuentra las burbujas Personne (solo hay una), escribe en ella nom = 'Alice', muéstrala.

Balance: Set 1 property.

A observar: la burbuja ahora lleva Alice como leyenda (Browser muestra por defecto la primera propiedad de texto). Haz clic en ella: nom: Alice. Equivalente SQL: UPDATE personne SET nom = 'Alice'.

Para entender bien
  • MATCH antes de SET. Para modificar una burbuja, primero hay que encontrarla. MATCH (p:Personne) es el SELECT … FROM personne; SET es el UPDATE. Cypher encadena ambos en la misma frase.
  • Los textos van entre comillas simples 'Alice' (las comillas dobles también funcionan). Los números se escriben sin comillas: 30, no '30'.
  • Una propiedad solo existe si tiene un valor. No hay una columna ville vacía para Bob más adelante: simplemente no tendrá la propiedad ville.

Paso 3 — Varios valores a la vez

cypher
MATCH (p:Personne {nom: 'Alice'}) SET p.age = 30, p.ville = 'Montréal' RETURN p

Qué pide la consulta: encuentra la burbuja Personne cuyo nom es Alice, escribe dos valores más.

Balance: Set 2 properties.

A observar: la burbuja, al hacer clic, muestra nom: Alice, age: 30, ville: Montréal. El {nom: 'Alice'} entre llaves es un filtro: «la que tiene nom igual a Alice», el WHERE nom = 'Alice' de SQL. No cambia nada aquí (una sola Personne), pero desde el siguiente paso se vuelve indispensable.

Paso 4 — Crear un nodo con sus valores de una vez

cypher
CREATE (b:Personne {nom: 'Bob', age: 25}) RETURN b

Qué pide la consulta: crea una burbuja Personne que ya tiene nom y age.

Balance: Created 1 node, set 2 properties, added 1 label.

Mira ahora tus dos burbujas en tabla:

cypher
MATCH (p:Personne) RETURN p.nom, p.age, p.ville

Vista Table:

text
p.nom    p.age  p.ville
"Alice"  30     "Montréal"
"Bob"    25     null

A observar: null para la ciudad de Bob: no tiene esa propiedad. En SQL sería una celda vacía de la columna ville; aquí, la casilla no existe en absoluto. Equivalente SQL: SELECT nom, age, ville FROM personne.

Paso 5 — Conectar a Alice con Bob

cypher
MATCH (a:Personne {nom: 'Alice'}), (b:Personne {nom: 'Bob'})
CREATE (a)-[:CONNAIT]->(b)

Qué pide la consulta: encuentra a Alice, llámala a; encuentra a Bob, llámalo b; crea una flecha de tipo CONNAIT que parte de a y llega a b.

Balance: Created 1 relationship, luego Completed after … ms. Sin resultado: no hay RETURN.

Mira la flecha:

cypher
MATCH (a:Personne)-[r]->(b:Personne) RETURN a, r, b

Qué pide la consulta: todas las flechas, sea cual sea su tipo ([r] sin :TYPE), que van de una Personne a una Personne.

A observar: vista Graph, dos burbujas y una flecha con CONNAIT escrito encima, en el sentido Alice → Bob. A la derecha, Results overview: Nodes (2), Relationships (1) con la pastilla CONNAIT (1). Equivalente SQL: INSERT INTO connait (personne_source, personne_cible) VALUES (id_alice, id_bob), en una tabla de unión que habrías tenido que crear antes.

Para entender bien
  • Una relación conecta dos burbujas que ya existen. De ahí el MATCH en la primera línea: sin él, CREATE (a)-[:CONNAIT]->(b) crearía dos burbujas nuevas y vacías y una flecha entre ellas. Error clásico.
  • El tipo va en MAYÚSCULAS por convención, con _: CONNAIT, A_SUIVI, ENSEIGNE. No es obligatorio, es lo que hace todo el mundo.
  • Una relación siempre tiene un sentido. (a)-[:CONNAIT]->(b): la punta está en b. No existe relación sin dirección en Neo4j; al leer, en cambio, se puede ignorar el sentido (paso 7).

Paso 6 — Un valor en la flecha

cypher
MATCH (:Personne {nom: 'Alice'})-[r:CONNAIT]->(:Personne {nom: 'Bob'})
SET r.depuis = 2024
RETURN r

Qué pide la consulta: encuentra la flecha CONNAIT que va de Alice a Bob, llámala r, escribe en ella depuis = 2024.

Balance: Set 1 property.

Lee todo en tabla:

cypher
MATCH (a:Personne)-[r:CONNAIT]->(b:Personne)
RETURN a.nom, type(r), r.depuis, b.nom
text
a.nom    type(r)    r.depuis  b.nom
"Alice"  "CONNAIT"  2024      "Bob"

A observar: type(r) da el tipo de la flecha; r.depuis su propiedad, exactamente como p.nom para una burbuja. Una relación se trata como un nodo: se encuentra, se nombra, se lee y se escribe en ella. Las burbujas sin nombre temporal, (:Personne {…}), son aquellas que no necesitas después: puedes omitir la letra.

Paso 7 — La flecha tiene un sentido

cypher
MATCH (:Personne {nom: 'Bob'})-[:CONNAIT]->(x) RETURN x.nom

Qué pide la consulta: ¿a quién conoce Bob? Las burbujas x al final de una flecha CONNAIT que parte de Bob.

text
(no changes, no records)

A observar: cero líneas. La única flecha va de Alice hacia Bob; ninguna parte de Bob. Ahora sin la punta:

cypher
MATCH (:Personne {nom: 'Bob'})-[:CONNAIT]-(x) RETURN x.nom
text
x.nom
"Alice"

-[:CONNAIT]- sin >: «una flecha CONNAIT entre Bob y x, en un sentido o en el otro». Alice aparece. Recuerda: al escribir, el sentido es obligatorio; al leer, tú eliges tenerlo en cuenta o no. Es lo que hace tan corto de escribir «quién está conectado con quién» en Cypher.

Paso 8 — Conectar tu burbuja con el grafo real

cypher
MATCH (a:Personne {nom: 'Alice'}), (c:Cours {id: 'C0001'})
CREATE (a)-[:AIME]->(c)

Qué pide la consulta: encuentra a Alice, encuentra el curso C0001 del conjunto de datos, crea una flecha AIME de una hacia el otro.

Balance: Created 1 relationship.

Alice ahora está conectada a una burbuja que existía antes que tú. Mira todo lo que sale de ella:

cypher
MATCH (a:Personne {nom: 'Alice'})-[r]->(x)
RETURN a.nom, type(r), labels(x)[0] AS type_cible, coalesce(x.nom, x.titre) AS cible
text
a.nom    type(r)    type_cible  cible
"Alice"  "AIME"     "Cours"     "Docker expliqué simplement"
"Alice"  "CONNAIT"  "Personne"  "Bob"

A observar: dos líneas, dos tipos de flecha, dos tipos de destino. labels(x)[0] da la etiqueta de la burbuja al final; coalesce(x.nom, x.titre) toma nom si existe, si no titre (Bob tiene un nom, el curso tiene un titre). Esta es tu tabla-entregable: guárdala. En SQL, habría hecho falta una unión por tabla de destino y un UNION; aquí, una sola línea de MATCH.

Pasa a la vista Graph con MATCH (a:Personne {nom: 'Alice'})-[r]->(x) RETURN a, r, x: Alice en el centro, Bob a un lado, el curso al otro, en dos colores (uno por etiqueta).

Paso 9 — Contar

cypher
MATCH (n) RETURN count(n) AS noeuds
text
noeuds
874

872 + tus 2 burbujas. Por etiqueta:

cypher
MATCH (n) RETURN labels(n)[0] AS label, count(*) ORDER BY label
text
label         count(*)
"Competence"  22
"Cours"       504
"Etudiant"    300
"Personne"    2
"Professeur"  30
"Ville"       16

A observar: una sexta línea, Personne 2. En una terminal, .\labo.ps1 etat o ./labo.sh etat ahora muestra ✔ Neo4j répond — nœuds : 874. El script y Neo4j Browser cuentan lo mismo por dos caminos: es la verificación cruzada de la práctica guiada, aplicada a lo que creaste tú mismo.

Paso 10 — Limpiar, y encontrar el error que lo explica todo

Prueba primero la eliminación ingenua:

cypher
MATCH (p:Personne) DELETE p
text
Neo.ClientError.Schema.ConstraintValidationFailed
Cannot delete node<874>, because it still has relationships. To delete this node, you must first delete its relationships.

A observar: un recuadro rojo, nada eliminado. Neo4j se niega a borrar una burbuja que todavía tiene flechas: una flecha sin burbuja al final no tendría sentido. El número node<874> es el identificador interno de la primera burbuja que intentó eliminar; en tu caso será diferente. Es el equivalente de una violación de clave foránea en SQL, con una diferencia: aquí, el remedio cabe en una palabra.

cypher
MATCH (p:Personne) DETACH DELETE p

Qué pide la consulta: encuentra las burbujas Personne, sepáralas (elimina sus flechas), luego elimínalas.

Balance: Deleted 2 nodes, deleted 2 relationships.

Dos nodos, dos relaciones: CONNAIT y AIME. El curso C0001 no se tocó, solo desapareció la flecha que lo apuntaba. Verifica:

cypher
MATCH (n) RETURN count(n) AS noeuds
text
noeuds
872

MATCH (n) RETURN labels(n)[0] AS label, count(*) ORDER BY label vuelve a dar cinco líneas, sin Personne, y etat dice nœuds : 872.

Para entender bien
  • DETACH DELETE es el gesto normal para eliminar un nodo en Neo4j; DELETE solo sirve para un nodo que sabes que está aislado, o para eliminar una relación: MATCH ()-[r:AIME]->() DELETE r borra la flecha y conserva las burbujas.
  • El módulo 6 te hará escribir MERGE en lugar de CREATE: «crea si no existe, si no, reutiliza». Es lo que permite que el script charger-graphe se pueda relanzar sin duplicados. Con CREATE, relanzar el paso 4 habría fabricado un segundo Bob.
  • Nada de lo que hiciste quedó. El grafo volvió a su estado de referencia, exactamente como después de DELETE pratique-mini en el taller fundamental 1. Toma la costumbre: lo que creas para aprender, lo eliminas al final.

Verificación final

  • Creaste un nodo con una sola etiqueta y viste que no tiene ninguna propiedad.
  • Le diste nom, luego age y ville, con SET, encontrándolo primero con MATCH.
  • Creaste a Bob con sus valores en una sola consulta, y viste null donde falta una propiedad.
  • Creaste CONNAIT entre dos burbujas existentes, pusiste depuis en ella, y leíste type(r) y r.depuis en tabla.
  • Sabes decir por qué (Bob)-[:CONNAIT]->(x) no devuelve nada y (Bob)-[:CONNAIT]-(x) devuelve a Alice.
  • Conectaste a Alice con el curso C0001 y guardaste la tabla de dos líneas del paso 8 como entregable.
  • Viste el error Cannot delete node … because it still has relationships, luego DETACH DELETE devolvió Deleted 2 nodes, deleted 2 relationships.
  • MATCH (n) RETURN count(n) y etat dicen 872.

Si algo falla

Mostrar los casos frecuentes
  • Invalid input, expected … en rojo → error de sintaxis. Las tres causas en el aula: un paréntesis ( cerrado con un corchete ], una punta de flecha olvidada al escribir (-[:CONNAIT]- en un CREATE se rechaza: Only directed relationships are supported in CREATE), una comilla faltante alrededor de un texto.
  • Variable `r` not defined (o a, p…) → usas una letra en SET o RETURN que ningún MATCH ni CREATE de la misma consulta introdujo. Ejemplo: SET r.depuis = 2024 mientras que la flecha se escribió -[:CONNAIT]-> sin la r. Añade la letra donde aparece el objeto: -[r:CONNAIT]->.
  • El paso 5 creó burbujas vacías de más (Created 2 nodes, created 1 relationship, y Results overview muestra * (4)) → escribiste CREATE (a)-[:CONNAIT]->(b) sin el MATCH justo antes, o con un punto y coma entre las dos líneas. a y b eran desconocidos: Neo4j no protesta, los inventa, sin etiqueta ni propiedad. Limpia: MATCH (n) WHERE size(labels(n)) = 0 DETACH DELETE n, luego repite el paso 5 en una sola consulta.
  • Dos Alice o dos Bob (MATCH (p:Personne) RETURN count(p) devuelve más de 2) → relanzaste un CREATE. MATCH (p:Personne) DETACH DELETE p y repite desde el paso 1; el módulo 6 te enseñará MERGE, que evita esto.
  • Cannot delete node … because it still has relationships → es el paso 10, buscado. DETACH DELETE.
  • La burbuja muestra un número o <id> en lugar de Alice → Browser todavía no sabe qué propiedad mostrar. Haz clic en la pastilla Personne bajo el grafo y elige nom como leyenda; o lee en vista Table.
  • etat sigue diciendo nœuds : 872 después de tus creaciones → estás conectado a otra base u otro Neo4j (¿un neo4j instalado localmente en el puerto 7687?). En Browser, la banda superior debe decir neo4j://localhost:7687 y Database: neo4j; si no, cierra el otro Neo4j o cambia su puerto.
  • Neo.ClientError.Security.Unauthorized → contraseña rechazada. Es aiopsatlas2026; si la cambiaste y la perdiste, ./labo.sh reinitialiser luego demarrer y charger-graphe (los datos del kit se recargan de forma idéntica).