A Graph Database stores graph data and is ideal for handling complex relationships such as social networks and knowledge graphs. Use graph query languages such as Cypher or Gremlin to work with this data. PolarDB supports OpenCypher syntax and provides features including creating, querying, updating, and deleting graph data, pattern matching, filtering, MERGE to avoid duplicates, and visualization tools—simplifying graph data management and application development.
Applicable scope
The following versions of PolarDB for PostgreSQL are supported:
-
PostgreSQL 16 (minor engine version 2.0.16.8.3.0 or later)
-
PostgreSQL 15 (minor engine version 2.0.15.12.4.0 or later)
-
PostgreSQL 14 (minor engine version 2.0.14.12.24.0 or later)
View your minor engine version in the console, or run the SHOW polardb_version; statement. If your version does not meet the requirement, upgrade the minor engine version.
Terms
-
Graph: A graph is a data structure made up of nodes and edges. For example, a social network is a typical graph where each person is a node and their relationships such as friends, family, or colleagues are edges.

-
Node: A node is a basic element in a graph database that represents an entity. Nodes can have properties that store information about the entity. In a social network, nodes might represent users, companies, or organizations.
-
Edge: An edge connects nodes and represents a relationship. Edges can have attributes such as weight or direction to indicate the strength or orientation of the relationship. In a social network, edges might represent follows, friendships, or fan relationships.
-
Label: A label is a category or attribute used to classify nodes or edges. Labels help give semantic meaning to your data, making queries and analysis easier. In a social network, node labels might include Person or Company, while edge labels might include Knows or WorkIn.
-
Property graph: A graph is called a property graph if its nodes contain properties (details about the entity) or its edges contain properties (details about the relationship). The following example shows a colleague relationship as a property graph, with relevant attributes on both nodes and edges:

-
Graph Database: A specialized database that uses graphs to store data—nodes represent entities and edges represent relationships. It excels at handling complex relational data such as social networks, trust networks, and knowledge graphs.
Graph databases use graph query languages such as Cypher or Gremlin to query data. PolarDB supports OpenCypher syntax. OpenCypher is an open-source subset of Cypher, and most of its features are equivalent to Cypher.
Schema
Properties
In Cypher, use curly braces {} to define properties. Properties consist of key-value pairs, similar to JSON. Keys are strings, and values can be strings, numbers, or arrays. For example, {name: 'Reeves'} means the name is Reeves.
Nodes
In Cypher, use parentheses () to represent nodes. Here are some examples:
()
(matrix)
(:Movie)
(matrix:Movie)
(matrix:Movie {title: 'The Matrix'})
(matrix:Movie {title: 'The Matrix', released: 1997})
Where:
-
The simplest form
()represents an anonymous, uncharacterized node. -
To reference the node elsewhere in the same statement, add a variable—for example,
(matrix). Variables apply only within a single statement and may have different or no meaning in other statements. -
:Moviedeclares the node’s label, restricting the pattern to match only nodes with that label. -
{title: 'The Matrix'}defines node properties, which can store information or constrain the pattern.
Edges
In Cypher, use two dashes -- for an undirected edge, or add an arrow—<-- or -->—for a directed edge. Use bracket expressions [...] to add details such as variables, properties, or type information. Examples:
--
-->
-[role]->
-[:ACTED_IN]->
-[role:ACTED_IN]->
-[role:ACTED_IN {roles: ['Neo']}]->
Where:
-
--is an anonymous undirected edge. -
-->is an anonymous directed edge. -
You can define a variable (for example,
role) to use elsewhere in the statement. -
Relationship labels (for example,
:ACTED_IN) work like node labels. -
Properties (for example,
roles: ['Neo']) are defined the same way as node properties.
Examples
The following example shows how to use graph features in PolarDB. The sample data is a simple movie database containing actors and films.
Create the extension
Use a privileged account to run the following statement. To create a privileged account, see Create a database account .
The age extension does not currently support manual creation. To use this feature, submit a ticket to contact us so we can create the extension for you.
CREATE EXTENSION age;
Configure the database
For each connection, add ag_catalog to the search_path to simplify queries, and load the extension using the get_cypher_keywords function:
Compatibility issues may occur when you use Data Management (DMS) to configure the search_path. In such cases, you can use PolarDB-Tools to execute related statements.
SET search_path = ag_catalog, "$user", public;
SELECT * FROM get_cypher_keywords() limit 0;
We strongly recommend that a privileged account configure database parameters to load the extension permanently. This avoids repeating the above steps on every connection and simplifies usage.
ALTER DATABASE <dbname> SET search_path = "$user", public, ag_catalog;
ALTER DATABASE <dbname> SET session_preload_libraries TO 'age';
Grant AGE access to regular users
Grant USAGE permission on the ag_catalog schema to regular users.
GRANT USAGE ON SCHEMA ag_catalog TO <username>;
If the regular user is an RW user, also grant the CREATE permission to allow table creation.
GRANT CREATE ON DATABASE <dbname> TO <username>;
Query structure
Cypher queries in PolarDB are built by calling the cypher function in ag_catalog, which returns a SETOF records. Here is a typical query:
SELECT * FROM cypher('graph_name', $$
/* Write your Cypher query here */
$$) AS (result1 agtype, result2 agtype);
Here, graph_name is the name of the graph, and replace the /* */ block with your actual Cypher query.
Create a graph
Before using a graph, create it first. Use the create_graph function in the ag_catalog namespace.
Syntax:
SELECT create_graph('<graph_name>');
Example:
Create a graph named moviedb.
SELECT create_graph('moviedb');
Insert data
Run the following SQL statement to insert sample data into the moviedb graph:
SELECT * FROM cypher('moviedb', $$
CREATE (matrix:Movie {title: 'The Matrix', released: 1997})
CREATE (cloudAtlas:Movie {title: 'Cloud Atlas', released: 2012})
CREATE (forrestGump:Movie {title: 'Forrest Gump', released: 1994})
CREATE (keanu:Person {name: 'Keanu Reeves', born: 1964})
CREATE (robert:Person {name: 'Robert Zemeckis', born: 1951})
CREATE (tom:Person {name: 'Tom Hanks', born: 1956})
CREATE (tom)-[:ACTED_IN {roles: ['Forrest']}]->(forrestGump)
CREATE (tom)-[:ACTED_IN {roles: ['Zachry']}]->(cloudAtlas)
CREATE (robert)-[:DIRECTED]->(forrestGump)
$$) AS (result1 agtype);
This creates six nodes—three labeled Movie and three labeled Person—and three edges: two labeled ACTED_IN and one labeled DIRECTED. The relationship diagram is shown below:

Query data
Data query
In Cypher, use the MATCH and RETURN keywords to query data:
-
MATCHperforms pattern matching to find content that matches a specified pattern. -
RETURNspecifies the values or results to return from the Cypher query.
Syntax:
SELECT * FROM cypher('graph_name', $$
MATCH <patterns>
RETURN <variables>
$$) AS (result1 agtype);
Examples:
-
Find all nodes with the
Movielabel.SELECT * FROM cypher('moviedb', $$ MATCH (m:Movie) RETURN m $$) AS (result1 agtype); -
Find edges labeled
ACTED_INthat connectPersonandMovienodes.SELECT * FROM cypher('moviedb', $$ MATCH (:Person)-[r:ACTED_IN]->(:Movie) RETURN r $$) AS (result1 agtype);
Data filtering
Use the WHERE clause to filter results when pattern matching and returning only a subset of interest. This clause lets you filter data using Boolean expressions.
Examples:
-
Find all movies titled
The Matrix.SELECT * FROM cypher('moviedb', $$ MATCH (m:Movie) WHERE m.title = 'The Matrix' RETURN m $$) AS (result1 agtype); -
Find all actors in the movie
Forrest Gump.SELECT * FROM cypher('moviedb', $$ MATCH (p:Person)-[:ACTED_IN]->(m) WHERE m.title = 'Forrest Gump' RETURN p $$) AS (result1 agtype); -
Find actors in movies released after 2000.
SELECT * FROM cypher('moviedb', $$ MATCH (p:Person)-[:ACTED_IN]->(m) WHERE m.released > 2000 RETURN p, m $$) AS (result1 agtype, result2 agtype);
Create nodes or edges
In Cypher, use the CREATE keyword to add new nodes or edges.
Syntax:
SELECT * FROM cypher('<graph_name>', $$
CREATE <patterns>
$$) AS (result1 agtype);
Examples:
-
Create a
Personnode with nameTom Tykwerand birth year1965.SELECT * FROM cypher('moviedb', $$ CREATE (:Person {name: 'Tom Tykwer', born: 1965}) $$) AS (result1 agtype); -
Create a
Tom Tykwer–Cloud Atlasedge indicating thatTom TykwerdirectedCloud Atlas.SELECT * FROM cypher('moviedb', $$ MATCH (p:Person), (m:Movie) WHERE p.name='Tom Tykwer' AND m.title='Cloud Atlas' CREATE (p)-[:DIRECTED]->(m) $$) AS (result1 agtype);
Use MERGE to avoid duplicate inserts
Running the same CREATE statement multiple times inserts duplicate data. To prevent this, use the MERGE keyword. MERGE checks whether data already exists. If it does, it returns the existing data or updates the node or relationship. If not, it creates new data based on the specified pattern.
Syntax:
SELECT * FROM cypher('<graph_name>', $$
MERGE <patterns>
$$) AS (result1 agtype);
Examples:
-
Create a
Personnode with nameTom Cruiseand birth year1962.SELECT * FROM cypher('moviedb', $$ MERGE (:Person {name: 'Tom Cruise', born: 1962}) $$) AS (result1 agtype); -
Create a friendship edge between
Tom HanksandTom Cruise.SELECT * FROM cypher('moviedb', $$ MATCH (t1:Person),(t2:Person) WHERE t1.name='Tom Hanks' AND t2.name='Tom Cruise' MERGE (t1)-[:FRIEND]-(t2) $$) AS (result1 agtype);
Update
To modify properties of existing nodes or relationships, match the desired pattern and use the SET keyword to add or update properties.
Syntax:
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
SET <property>
RETURN <variable>
$$) AS (result1 agtype);
Examples:
-
Change the birth year of
Tom Tykwerto 1970.SELECT * FROM cypher('moviedb', $$ MATCH (p:Person {name: 'Tom Tykwer', born: 1965}) SET p.born = 1970 RETURN p $$) AS (result1 agtype); -
Add a gender property with value
maletoTom Tykwer.SELECT * FROM cypher('moviedb', $$ MATCH (p:Person {name: 'Tom Tykwer', born: 1970}) SET p.gender = 'male' RETURN p $$) AS (result1 agtype);
Delete
In Cypher, use the DELETE keyword to remove nodes and edges.
Delete edges
To delete an edge, use MATCH to find the edge and DELETE to remove it.
Syntax
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
DELETE <variable>
$$) AS (result1 agtype);
Example
Delete the DIRECTED edge between Tom Tykwer and the movie Cloud Atlas.
SELECT * FROM cypher('moviedb', $$
MATCH (p:Person)-[r:DIRECTED]->(m:Movie)
WHERE p.name='Tom Tykwer' AND m.title='Cloud Atlas'
DELETE r
$$) AS (result1 agtype);
Delete nodes
To delete a node, use MATCH to find the node and DELETE to remove it.
Syntax
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
DELETE <variable>
$$) AS (result1 agtype);
Example
Delete the Tom Tykwer node.
SELECT * FROM cypher('moviedb', $$
MATCH (p:Person {name: 'Tom Tykwer', born: 1970})
DELETE p
$$) AS (result1 agtype);
Delete nodes and their edges
You cannot delete a node directly if it has connected edges. Use DETACH DELETE to remove all connected edges and then delete the node.
Syntax
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
DETACH DELETE <variable>
$$) AS (result1 agtype);
Example
Delete the Tom Hanks node and all its connected edges.
SELECT * FROM cypher('moviedb', $$
MATCH (p:Person {name: 'Tom Hanks', born: 1956})
DETACH DELETE p
$$) AS (result1 agtype);
Delete properties
To remove a property from a node or edge, use the REMOVE keyword.
Syntax
SELECT * FROM cypher('<graph_name>', $$
MATCH <match_pattern>
REMOVE <property>
$$) AS (result1 agtype);
Example
Remove the released property from the movie Cloud Atlas.
SELECT * FROM cypher('moviedb', $$
MATCH (m:Movie {title: 'Cloud Atlas', released: 2012})
REMOVE m.released
RETURN m
$$) AS (result1 agtype);
Visualization tool
PolarDB for PostgreSQL integrates the open-source graph engine Apache AGE, letting you use both standard SQL and the industry-standard OpenCypher graph query language in the same cluster. This enables efficient storage, querying, and analysis of graph data for complex relationship scenarios. For more information, see Graph applications.
In AGE Viewer, run the Cypher query SELECT * from cypher('moviedb', $$ MATCH (V) RETURN V UNION MATCH ()-[r]->() RETURN r $$) as (V agtype); on the moviedb graph. The visualization shows three Movie nodes and three Person nodes (Tom Hanks, Keanu Reeves, Robert Zemeckis), along with two ACTED_IN edges and one DIRECTED edge, laid out using the Cose-Bilkent layout.