age icon indicating copy to clipboard operation
age copied to clipboard

How to work with dynamic property

Open nieyankai opened this issue 3 years ago • 7 comments

I'm working on a system that need to deal with dynamic properties.

If I want to create a vertex, I can do it like this before that: select * from ag_catalog.cypher('people',$$ create (nyk:person{name:'nyk'}) return nyk $$) as (v ag_catalog.agtype);

But now, I don't know the property, the property is given by the user as a json object. The property may be {name:'asdf'} or {name:'asdf', age:25} or {name:'asdf', work:'programmer'} .... I don't know what property will get. The problem is same when using the delete,update or get method. So how to deal with that? Can I bind the property with a json parameter?

nieyankai avatar Sep 03 '21 03:09 nieyankai

You mean, -> anyone who gives you a data, -> and you have to translate that value, -> and find values from vertex that created. -> but you forgot property label/values of specific vertex

If I understood that, as a basic, it is way to you try do.

  1. If you know vertex name, try it.
  • test_graph is your graph path. select * from cypher('test_graph', $$ match(n:person) return n $$) as (n agtype) ;
  1. You can get values as a agtype. ex) {"id": xxxxxxxxxxxxx, "label" :"person", "properties": {"name": "nyk", "age:25.....}}::vertex

  2. "properties" is included you created values.

  3. If you want to find specific property name, try it. select * from cypher('test_graph', $$ match(n:person{name:'nyk'}) return n $$) as (n agtype) ; or select * from cypher('test_graph', $$ match(n:person) where n.name='nyk' return n $$) as (n agtype) ;

If I understood exactly your question, maybe you can achive your question that queries.

Halkrine avatar Sep 03 '21 05:09 Halkrine

I understood the question as "How can I attach properties and values to a vertex if I don't know the properties beforehand". Are the properties predefined (e.g., the user can enter some properties such as "name", "age", "job" information, but no others), are is the user completely free to enter data?

I see two possible solutions (I assume the "system" you are talking about consists of some application logic):

  1. Parse the data entered by the user and construct the correct query (specifically the part name:$name, age: $age in the example below) in your application logic. Make sure to check if the properties ("name", "age", "job") only contain certain characters (or if the allowed properties are predefined: check if they are in this predefined list) to prevent SQL injections. Example of a query with properties "name" and "age":
SELECT * from ag_catalog.cypher(
    'people',
    $$ CREATE (nyk:person{name:$name, age: $age}) RETURN nyk, $1 $$
) as (v ag_catalog.agtype);

where you then pass the values as json text string:

'{"name": "Jane", "age": 35}'
  1. Enter the data entered by the user as a map under a specific property (e.g., "data"). I don't know if this has repercussions on the querying performance. Example:
SELECT * from ag_catalog.cypher(
    'people',
    $$ CREATE (nyk:person{data:$data}) RETURN nyk, $1 $$
) as (v ag_catalog.agtype);

with as parameter

'{"data": {"name": "Jane", "age": 35}}'

pdpotter avatar Sep 06 '21 07:09 pdpotter

I understood the question as "How can I attach properties and values to a vertex if I don't know the properties beforehand". Are the properties predefined (e.g., the user can enter some properties such as "name", "age", "job" information, but no others), are is the user completely free to enter data?

I see two possible solutions (I assume the "system" you are talking about consists of some application logic):

  1. Parse the data entered by the user and construct the correct query (specifically the part name:$name, age: $age in the example below) in your application logic. Make sure to check if the properties ("name", "age", "job") only contain certain characters (or if the allowed properties are predefined: check if they are in this predefined list) to prevent SQL injections. Example of a query with properties "name" and "age":
SELECT * from ag_catalog.cypher(
    'people',
    $$ CREATE (nyk:person{name:$name, age: $age}) RETURN nyk, $1 $$
) as (v ag_catalog.agtype);

where you then pass the values as json text string:

'{"name": "Jane", "age": 35}'
  1. Enter the data entered by the user as a map under a specific property (e.g., "data"). I don't know if this has repercussions on the querying performance. Example:
SELECT * from ag_catalog.cypher(
    'people',
    $$ CREATE (nyk:person{data:$data}) RETURN nyk, $1 $$
) as (v ag_catalog.agtype);

with as parameter

'{"data": {"name": "Jane", "age": 35}}'

You got it. The property is not predefined, no one knows the property key util the user enter it. So the 2nd solution is a choice, but this will encounter another problem: how to match the properties? I want to use like this but I can't: SELECT * from ag_catalog.cypher( 'people', $$ MATCH(nyk:person{$key1:$value1,$key2:$value2....}) RETURN nyk, $1, $2, $3, $4... $$ ) as (v ag_catalog.agtype); or SELECT * from ag_catalog.cypher( 'people', $$ MATCH(nyk:person{some map user entered}) RETURN nyk, $1 $$ ) as (v ag_catalog.agtype);

nieyankai avatar Sep 13 '21 10:09 nieyankai

Example for the second solution:

Create person nodes

SELECT * FROM ag_catalog.cypher(
    'people',
    $$ CREATE (a:Person {data:{name:'Jane', 'age': 35}}) $$
) as (a ag_catalog.agtype);

 a 
---
(0 rows)

SELECT * FROM ag_catalog.cypher(
    'people',
    $$ CREATE (a:Person {data:{name:'Will', age: 21}}) $$
) as (a ag_catalog.agtype);

 a 
---
(0 rows)

Retrieve all persons with age 21

SELECT * FROM ag_catalog.cypher(
    'people',
    $$MATCH(n {data:{age:21}}) RETURN n$$
) as (n ag_catalog.agtype);

                                                    n                                                    
---------------------------------------------------------------------------------------------------------
 {"id": 844424930131974, "label": "Person", "properties": {"data": {"age": 21, "name": "Will"}}}::vertex
(1 row)

Retrieve all persons with age greater than 25

SELECT * FROM cypher(
    'people',
    $$MATCH(n) WHERE n.data.age > 25 RETURN n$$
) as (n agtype);

                                                    n                                                    
---------------------------------------------------------------------------------------------------------
 {"id": 844424930131973, "label": "Person", "properties": {"data": {"age": 35, "name": "Jane"}}}::vertex
(1 row)

pdpotter avatar Sep 13 '21 11:09 pdpotter

I think this issue has been resolved, I close the issue.

pdpotter avatar Apr 29 '22 08:04 pdpotter

Hi @pdpotter, Let's not close this idea yet. This ticket is introducing an idea about stored procedures and extending the CREATE clause in a way that allows users to make a system that anticipates an unanticipated number of properties. Lets leave this open for a while.

JoshInnis avatar Apr 29 '22 08:04 JoshInnis