Queries: Creating queries
Creating queries
Query language
Queries in Linkurious Enterprise are written using a graph query language. Linkurious Enterprise supports several graph databases: Neo4j, Memgraph, Neptune and Cosmos DB. Neo4j and Memgraph support the Cypher query language while Cosmos DB support the Gremlin query language.
Neptune now supports both Gremlin and Cypher, giving you the flexibility to choose the query language that best fits your needs. When querying Neptune, you can easily select which query language to use based on your preferences. Below is a screenshot showing how to pick the query language when querying Neptune:
The Cypher query language is similar to SQL, it can be learned from Neo4j's online documentation.
Access Rights for queries
There are four levels of access rights associated with queries in Linkurious Enterprise.
Access Right Level | Description |
---|---|
Cannot run queries | User can not create or run queries |
Can run existing queries | User can execute any existing query that has been shared with them. User can not create new queries. |
Can create read-only queries and run existing queries | User can execute any existing query that has been shared with them. User can not create queries that will alter the data (a.k.a. write-queries). |
Can create read/write queries and run existing queries | User can execute any existing query that has been shared with them. User can create queries. |
Can manage, create read/write queries and run queries | User can execute, edit and delete any existing query that has been shared with as least 1 group. This includes hidden queries. |
The above access rights are applied to groups. The group a user belongs to defines their query access rights.
Writing queries
A query can have dynamic inputs (e.g. {{"Country":string:["France","Germany"]}}
) that
are used to parameterize the query. When a query has dynamic input, it will require the
input to be provided to run. Query inputs can be of different types, such as nodes, edges,
text, numbers, etc.
If a query creates, deletes or updates the graph, it is called a write-query. Creating a write-queries is subject to the user's access rights.
A query must return nodes and edges. Any other value return by the query (numbers, text) will be ignored.
Query creation
The query creator is where users can create, test and save new queries.
It can be accessed by clicking on the {🖊}
icon in the top-left of a visualization.
The Query creator menu is split in two parts:
- The upper part is where users can write their query using the graph query language.
- The lower part is where users can preview the results of their query.
Cypher query autocompletion
The query editor helps you create queries using the autocompletion for the Cypher query language. The Cypher autocompletion is aware of the schema and depending on the user's action suggests node categories, edge types or Cypher keywords.
- Cypher's keywords have menu completion
- When the user types Variable + colon the Node Categories menu appears
- When the user types Variable + colon the Edge Types menu appears
Saving a query
When users have written, tested and perfected a query, they can save it for later use in the next step by selecting NEXT
.
When saving a query, the user is prompted for a Query title, a Description, Tags and Sharing settings.
Query tags make queries easier to find after creation. When saving a query, you can add one or more existing tags to it and create new ones.
- Created tags will be visible by any user who can create or edit queries.
- All users who can edit a query can also add or remove tags for that query.
- Query tags are saved on a datasource level. This means that each datasource will have different tags.
- Query tags will be given a color automatically by Linkurious Enterprise.
Queries can be kept private, shared with everybody or shared specific user groups. Some important information on shared queries:
- The description of a query can be seen by everyone who has access to it.
- Only the creator of a query can edit and delete it.
Saved queries can be consulted from the right panel of the workspace.
Examples of queries
The section below provides examples of different types of queries that users can create and use.
Read-only query without input
The following query returns all City
nodes that have between 3 and 100 Company
nodes
connected to them via HAS_CITY
edges:
MATCH (city:City)<-[hasCity:HAS_CITY]-(company:Company)
WITH
city,
count(company) as score,
collect(company) as companies,
collect(hasCity) as hasCities
WHERE score > 3 AND score < 100
RETURN city, companies, hasCities
Write-query with input
The following query changes the profession of a person and adds some change logs in a property:
MATCH (n)
WHERE ID(n) = {{"Suspicious entity":node:["Person"]}}
WITH
n,
apoc.date.currentTimestamp() AS currentTimestamp
SET n.change_log =
"Modification done by: " + {{"User":env:"email"}} +
" on: " + toString(datetime({epochMillis: currentTimestamp})) +
". Previous value: " + n.profession +
". Comment: " + {{"Comment":string:{"placeholder": "Add a note..."}}}
SET n.profession = {{"Profession":string}}
RETURN n;
Queries that write in the database can be shared with any user group, including those that were not granted "Write" permissions on any node category. Be considerate as to who you share queries with, and who has the right to share queries (see "Access Right" section in administration manual).
Single-node query
The following query returns up to max
nodes of type COMPANY
that are neighbours of the
input node:
MATCH (n)-[edge]-(company:Company)
WHERE id(n) = {{"Node":node}}
RETURN edge, company
LIMIT {{"max":number:10}}
Single-node queries can be run on multiple nodes at once, the same way it is possible to expand multiple nodes at once.
Two-nodes query
The following query is a built-in query that finds the shortest path between two nodes:
MATCH (a), (b), p = allShortestPaths((a)-[*..{{"Maximum path length":number:{"default": 4, "min": 1, "max": 10}}}]-(b))
WHERE id(a) = {{"Source":node}} AND id(b) = {{"Target":node}}
RETURN p LIMIT {{"Maximum number of paths":number:{"default": 5, "min": 1, "max": 50}}}
Multiple-nodes query
The following query returns only the nodes that are shared neighbours to each and every node of the input nodeset:
MATCH (n) WHERE id(n) IN {{"My nodes":nodeset}}
MATCH (n)-[e]-(m)
WITH m, collect(e) AS edges, count(distinct n) AS sharedNeighborCount
WHERE sharedNeighborCount = size({{"My nodes":nodeset}})
RETURN m, edges
Single-edge query
The following query returns all the parallel edges of the selected node:
MATCH (a)-[e]->(b) WHERE id(e) in {{"edge":edge}}
MATCH (a)-[e2]->(b)
RETURN a, e2, b
Multiple-edges query
The following query returns only the edges that share a node with the edgeset
input:
MATCH (n)-[e:INVESTED_IN]-() WHERE id(e) IN {{"My edges":edgeset}}
MATCH (n)-[e2:INVESTED_IN]-(m)
RETURN e, e2, n, m
Query input syntax
This section provides a deep-dive into the different types of input variables can be used in queries.
To declare inputs in a query, use double curly braces to mark the start and end of input, for example:
MATCH (n)-[e]-(m) WHERE id(n) = {{"My node":node}} RETURN e, m
An input variable is made of 3 terms separated by a colon (:
), the first 2 being mandatory:
- Variable ID (mandatory). A quoted string. It serves as the label of the input in the user form. It allows you to reuse the same variable in multiple places in your code.
- Variable type (mandatory). Must be one of
node
,nodeset
,edge
,edgeset
,string
,number
,date
,datetime
,enum
,env
,list
. - Variable parameters (optional). Variable-specific parameters.
A Query requiring input can take both graph and non-graph input:
- Node variables (
node
ornodeset
) - Edge variables (
edge
oredgeset
) - Non-graph variables (e.g.
number
,string
, etc.)
node
variable
Used to inject a single node ID in a graph query:
- Keyword:
node
. - Parameters:
categories
(optional): string or array of strings restricting the availability of input to the specified categories (as a consequence, the query will show in the context menu only if the selected node has one of the specified categories).
Examples:
{{"my node":node:"COMPANY"}}
{{"my node":node:["COMPANY","SUPPLIER"]}}
{{"my node":node:{"categories": ["COMPANY","SUPPLIER"]}}}
nodeset
variable
Used to inject a list of node IDs in a graph query:
- Keyword:
nodeset
- Parameters:
categories
(optional): Same as fornode
type.
Examples:
{{"my nodes":nodeset:"COMPANY"}}
{{"my nodes":nodeset:["COMPANY","SUPPLIER"]}}
{{"my nodes":nodeset:{"categories": ["COMPANY","SUPPLIER"]}}}
edge
variable
Used to inject a single edge ID in a graph query:
- Keyword:
edge
. - Parameters:
types
(optional): string restricting the availability of the input to the specified categories (as a consequence, the query will show in the context menu only if the selected edge has the specified type).
Examples:
{{"My edge":edge:["INVESTED_IN"]}}
{{"My edge":edge:{"types": ["INVESTED_IN"]}}}
edgeset
variable
Used to inject a list of edge IDs in a graph query:
- Keyword:
edgeset
- Parameters:
types
(optional): Same as foredge
type.
Examples:
{{"My edges":edgeset:["INVESTED_IN"]}}
{{"My edges":edgeset:{"types": ["INVESTED_IN"]}}}
enum
variable
Used to inject a string, numerical or boolean value in a graph query, from a list of choices:
- Keyword:
enum
- Parameters:
values
(required): An array of values to choose from or an array of value + label.default
(optional): A default value, must be one of thevalues
Examples:
{{"my enum":enum:["FR", "EN", "US"]}}
{{"my enum":enum:[1, 2, 3]}}
{{"my enum":enum:[true, false]}}
{{"my enum":enum:{"values": ["FR", "EN", "US"], "default": "EN"}}}
{{"my enum":enum:{"values": [{"label": "France", "value": "FR"}, {"label": "U.S.A", "value": "US"}]}}}
boolean
variable
Used to inject a true/false value in a graph query:
- Keyword:
boolean
- Parameters:
default
(optional): A default value
Examples:
{{"my choice":boolean}}
{{"my choice":boolean:true}}
{{"my choice":boolean:{"default": true}}}
date
variable
Used to inject a date-time in a graph query:
- Keyword:
date
- Parameters:
format
(required): The serialization format of the date in the query, must be one of:native
: serialized as a nativeDate
database objecttimestamp
: serialized as a numerical Unix timestamp in secondstimestamps-ms
: serialized as a numerical Unix timestamp in millisecondsiso
: serialized as a "yyyy-mm-dd" string (same asyyyy-mm-dd
)yyyy-mm-dd
: serialized as a "yyyy-mm-dd" string (same asiso
)dd/mm/yyyy
: serialized as a "dd/mm/yyyy" stringmm/dd/yyyy
: serialized as a "mm/dd/yyyy" string
default
(optional): A default value (expressed in "yyyy-mm-dd" format)min
(optional): The minimum accepted value (expressed in "yyyy-mm-dd" format)max
(optional): The maximum accepted value (expressed in "yyyy-mm-dd" format)
Examples:
{{"my date":date:"yyyy-mm-dd"}}
{{"my date":date:{"format": "yyyy-mm-dd"}}}
{{"my date":date:{"format: "timestamp-ms", "min": "2018-01-02"}}}
{{"my date":date:{"format": "yyyy-mm-dd", "default": "2018-01-01"}}}
{{"my date":date:{"format": "native", "min": "1990-12-31", "max": "2018-12-31"}}}
datetime
variable
Used to inject a date-time in a graph query:
- Keyword:
datetime
- Parameters:
format
(required): The serialization format of the date-time in the query, must be one of:native
: serialized as a nativeDateTime
database objecttimestamp
: serialized as a numerical Unix timestamp in secondstimestamps-ms
: serialized as a numerical Unix timestamp in millisecondsiso
: serialized as a "yyyy-mm-ddThh:mm:ss" string
timezone
(optional): A string in+HH:MM
or-HH:MM
format. If omitted and the format is "native', aLocalDateTime
object is created.default
(optional): A default value (expressed in "yyyy-mm-ddThh:mm:ss" format)min
(optional): The minimum accepted value (expressed in "yyyy-mm-ddThh:mm:ss" format)max
(optional): The maximum accepted value (expressed in "yyyy-mm-ddThh:mm:ss" format)
Examples:
{{"my date-time":datetime:"native"}}
{{"my date-time":datetime:{"format": "native"}}}
{{"my date-time":datetime:{"format": "iso"}}}
{{"my date-time":datetime:{"format":"native", "min": "2017-01-02T10:10:10"}}}
{{"my date-time":datetime:{"format":"native", "min": "1940-01-01T00:00:00", "max": "2020-01-01T00:00:00", "default": "2000-01-01T00:00:00", "timezone":"+02:00"}}}
number
variable
Used to inject a numerical value in a graph query:
- Keyword:
number
- Parameters:
default
(optional): A default valueplaceholder
(optional): The placeholder text to use in the form.min
(optional): The minimum accepted valuemax
(optional): The maximum accepted value
Examples:
{{"my number":number}}
{{"my number":number:12}}
{{"my number":number:{"default": 12}}}
{{"my number":number:{"min": 0}}}
{{"my number":number:{"min": 0, "max": 15.5, "default": 12}}}
string
variable
Used to inject a string of text in a graph query:
- Keyword:
string
- Parameters:
default
(optional): A default valueplaceholder
(optional): The placeholder text to use in the form.
Examples:
{{"my string":string}}
{{"my string":string:"paris"}}
{{"my string":string:{"default": "paris"}}}
{{"my string":string:{"placeholder": "Enter a city"}}}
env
variable
Used to inject information about the user who runs the query into a graph query:
- Keyword:
env
- Parameters:
value
: The type of value that will be injected into a graph query.
- Allowed Values:
email
: Used to inject email address of the user who runs the query.
Examples:
{{"User":env:{"value":"email"}}}
{{"User":env:"email"}}
list
variable
Used to inject a string or numerical array in a graph query, from a list of choices with the possibility of making multiple choices:
- Keyword:
list
- Parameters:
values
(required): An array of values to choose from or an array of value + label.default
(optional): A default value array, must be a subset of thelist
elements.
Examples:
{{"my list":list:["FR", "EN", "TR"]}}
{{"my list":list:[1, 2, 3]}}
{{"my list":list:{"values": ["FR", "EN", "TR"], "default": ["EN"]}}}
Previewing and testing queries
Once users are satisfied with their query, they can preview the results of their query by clicking on the PREVIEW YOUR QUERY button. The preview allows users to visualize the results of their query and:
- View the details of a node just like they can view details in the workspace;
- Expand nodes to better understand the context and validate the result of the query. The original results have a blue halo to differentiate them from nodes added later on through the expand action;
- Add the results of the query directly to the workspace without saving the query by clicking the Add results to the workspace button.
When a query contains input variables, a form is generated and displayed to the right of the query editor, allowing the query to be tested.
Write queries can not be tested.
Queries best practises
- If an input variable is followed directly by a closing curly brace character, users
must add a space between the end of the input and the following closing curly brace
character as shown in the example below.
MATCH (n:PERSON)-[:HAS_ACCOUNT]->(b:BANK {name: {{"name":string}} }) RETURN n, b
- For Cypher: Any query containing the
CALL
statement will be evaluated based on the access mode (for more info, refer to Neo4j documentation) of called procedure. The query will either be allowed or denied, depending on the access mode of the query and the access right of the user.- Queries that include a call to any procedure with modes
DEFAULT
andREAD
are considered READ queries in Linkurious Enterprise. - Queries that include a call to any procedure with other modes such as
DBMS
,WRITE
,SCHEMA
are considered WRITE queries in Linkurious Enterprise.
- Queries that include a call to any procedure with modes
- Queries can require a lot of computing resources from the database. Make sure to test your queries properly, and verify that you have enough computing power before sharing them. If overloaded, your database server may run slow or even crash, making the database unavailable.