Saltearse al contenido

Escribir datos

Cypher en NamiDB soporta las cláusulas de escritura estándar de openCypher 9 / GQL: CREATE, MERGE, SET, REMOVE, DELETE, DETACH DELETE. Cada statement de escritura se persiste antes de que la llamada retorne (WAL append + manifest CAS). En v0 no hay BEGIN / COMMIT explícitos; la unidad de atomicidad es el statement.

Consulta RFC-009 para el modelo de ejecución.

CREATE

Crea nodos y relaciones. Las properties pueden ser literales o $param.

CREATE (a:Person {name: 'Alice', age: 30})
CREATE (a:Person {name: 'Alice'})-[:KNOWS {since: 2020}]->(b:Person {name: 'Bob'})

CREATE después de un MATCH encadena ambos bindings en el patrón nuevo:

MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
CREATE (a)-[:KNOWS {since: 2020}]->(b)

Una consulta solo-escritura (sin MATCH previo) arranca con un row driver implícito — el mismo patrón que usa UNWIND.

MERGE

Upsert. Si el patrón matchea, devuelve los nodos / relaciones existentes; si no matchea, crea el patrón.

MERGE (p:Person {name: 'Alice'})
ON CREATE SET p.firstSeen = $now, p.lastSeen = $now
ON MATCH SET p.lastSeen = $now

En v0, MERGE acepta una sola pattern part (sin patrones multi-parte). MERGE (a:A:B {...}) multi-label es rechazado en tiempo de parse con E007_MergeMultiLabel.

Concurrencia: MERGE se apoya en el invariante single-writer-per-namespace para la serialización. Con un solo writer por namespace, dos MERGE concurrentes contra la misma clave se linealizan por el mutex del writer.

SET

Muta properties o agrega labels.

Asignación de property:

MATCH (p:Person {name: 'Alice'})
SET p.age = 31

Reemplazar el map de properties completo:

MATCH (p:Person {name: 'Alice'})
SET p = {name: 'Alice', age: 31, country: 'MX'}

Merge de un map parcial (solo las claves listadas cambian):

MATCH (p:Person {name: 'Alice'})
SET p += {age: 31, country: 'MX'}

Agregar labels:

MATCH (p:Person {name: 'Alice'})
SET p:Employee:Manager

REMOVE

El inverso de SET. Quita properties o labels.

MATCH (p:Person {name: 'Alice'})
REMOVE p.country
MATCH (p:Person {name: 'Alice'})
REMOVE p:Manager

DELETE y DETACH DELETE

DELETE aplica un tombstone a un nodo o relación. Un DELETE directo contra un nodo que todavía tiene aristas falla con un mensaje explícito ExecError::Mutation que sugiere usar DETACH DELETE:

MATCH (p:Person {name: 'Alice'})
DELETE p -- falla si Alice tiene aristas incidentes

DETACH DELETE enumera las aristas incidentes a través de cada edge_type en el schema del manifest, las tombstone-a, y después tombstone-a el nodo:

MATCH (p:Person {name: 'Alice'})
DETACH DELETE p -- elimina a Alice y cada arista que la toca

Borrar una arista directamente funciona sin DETACH:

MATCH (a:Person {name: 'Alice'})-[r:KNOWS]->(b:Person {name: 'Bob'})
DELETE r

UNWIND para escrituras en bulk

UNWIND expande una lista de parámetros a filas, que CREATE luego materializa. Es el camino idiomático de Cypher para inserts masivos:

UNWIND $people AS p
CREATE (:Person {name: p.name, age: p.age})
client.cypher(
"UNWIND $people AS p CREATE (:Person {name: p.name, age: p.age})",
params={"people": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
{"name": "Carol", "age": 42},
]},
)

Para ingesta de alto volumen, la API de staging en Python (client.merge_nodes / client.merge_edges) es más rápida — agrupa las mutaciones detrás de un solo round-trip del mutex de tokio por llamada. Consulta Librería Python.

Auto-commit y el write outcome

Cada statement de escritura corre a través de execute_write, que:

  1. Recorre el plan de arriba a abajo, llamando upsert_node / upsert_edge / tombstone_* contra el WriterSession por fila.
  2. Llama automáticamente writer.commit_batch().await antes de retornar.

El valor de retorno trae un resumen de contadores:

WriteOutcome {
rows: ...,
nodes_created: u64,
edges_created: u64,
nodes_deleted: u64,
edges_deleted: u64,
properties_set: u64,
}

Los contadores incrementan por operación, no por cambio neto de estado (así que SET p.x = p.x cuenta como un properties_set). Los contadores se exponen en el envelope HTTP como write_outcome — consulta la API HTTP.

Read-your-own-writes (todavía no)

Dentro de un solo statement, las escrituras no son visibles a las lecturas que vienen después en el mismo plan tree. Ejemplo:

CREATE (a:Person {name: 'Ada'})
MATCH (p:Person) RETURN p.name

El MATCH corre contra el snapshot fijado antes del CREATE. Workaround: divide en dos statements. Las escrituras Cypher hacen auto-commit, así que el segundo statement (o la siguiente llamada a Client.cypher) ve el nodo nuevo.

RFC-009 documenta por qué y traza el camino hacia un modelo transaccional futuro.

Siguientes pasos