I am trying to come up with a datatype for a general tree. I tried writing
datatype 'a TREE = null | Node of 'a * 'a TREE list;
but it didn't work out. My idea is to create a list of child nodes for a parent node and then each of the nodes in this list will be the parent node for another lists of nodes and so on.
How can this be achieved?
Related
I'm trying to create a new node with label C and relationships from a-->c and b-->c, but if and only if the whole pattern a-->c,b-->c does exist.
a and b already exist (merged before the rest of the query).
The below query is a portion of the query I want to write to accomplish this.
However, it creates a random empty node devoid of properties and labels and attaches the relationship to that node instead. This shouldn't be possible and is certainty not what I want. How do I stop that from happening?
merge (a: A {id: 1})
merge (b: B {id:1})
with *
call {with a, b
match (a)-[:is_required]->(dummy:C), (a)-[:is_required]->(b)
with count(*) as cnt
where cnt = 0
merge (temp: Temporary {id: 12948125})
merge (a)-[:is_required]->(temp)
return temp
}
return *
Thanks
I think there are a couple of problems here:
There are restrictions on how you can use variables introduced with WITH in a sub-query. This article helps to explain them https://neo4j.com/developer/kb/conditional-cypher-execution/
I think you may be expecting the WHERE to introduce conditional flow like IF does in other languages. WHERE is a filter (maybe FILTER would have been a better choice of keyword than WHERE). In this case you are filtering out 'cnt's where they are 0, but then never reference cnt again, so the merge (temp: Temporary {id: 12948125}) and merge (a)-[:is_required]->(temp) always get executed. The trouble is, due to the above restrictions on using variables inside sub-queries, the (a) node you are trying to reference doesn't exist, it's not the one in the outer query. Neo4j then just creates an empty node, with no properties or labels and links it to the :Temporary node - this is completely valid and why you are getting empty nodes.
This query should result in what you intend:
merge (a: A {id: 1})
merge (b: B {id:1})
with *
// Check if a is connected to b or :C (can't use a again otherwise we'd overwrite it)
optional match(x:A {id: 1}) where exists((a)-[:is_required]->(:C)) or exists((a)-[:is_required]->(b))
with *, count(x) as cnt
// use a case to 'fool' foreach into creating the extra :Temporary node required if a is not related to b or :C
foreach ( i in case when cnt = 0 then [1] else [] end |
merge (temp: Temporary {id: 12948125})
merge (a)-[:is_required]->(temp)
)
with *
// Fetch the :Temporary node if it was created
optional match (a)-[:is_required]->(t:Temporary)
return *
There are apoc procedures you could use to perform conditional query execution (they are mentioned in the linked article). You could also play around with looking for a path from (a) and check its length, rather than introduce a new MATCH and the variable x then checking for the existance of related nodes.
If anyone is having the same problem, the answer is that the Neo4j browser is display nonexistent nodes. The query executes fineā¦
I want to store hierarchical data in the PostgreSQL database.
I found ltree extension but it is used to store tree-structured data i.e there can be only one parent node.
Is there any way I can tweak it to store multiple parent nodes?
Yes, it is possible to do so using the ltree extension, by using two tables: one for your nodes and another for your paths. Bustawin has a great writeup on how to work with DAGs using this extension with this strategy.
For a node to have multiple parents, it is necessary that we define more than one ltree path for such node, one that leads from each parent. Say we have a DAG that forms a diamond between nodes A, B, C, and D:
A -> B
B -> D
A -> C
C -> D
Using the extension, you should have a node D related to two paths, A.B.D and A.C.D. Both queries should return node D
SELECT * FROM nodes
JOIN paths ON paths.node_id = nodes.id
WHERE paths.ltree_path ~ "A.B.*{1}"
SELECT * FROM nodes
JOIN paths ON paths.node_id = nodes.id
WHERE paths.ltree_path ~ "A.C.*{1}"
I am a newbie in the graph databases world, and I made a query to get leaves of the tree, and I also have a list of Ids. I want to merge both lists of leaves and remove duplicates in a new one to sum property of each. I cannot merge the first 2 sets of vertex
g.V().hasLabel('Group').has('GroupId','G001').repeat(
outE().inV()
).emit().hasLabel('User').as('UsersList1')
.V().has('UserId', within('001','002')).as('UsersList2')
.select('UsersList1','UsersList2').dedup().values('petitions').sum().unfold()
Regards
There are several things wrong in your query:
you call V().has('UserId', within('001','002')) for every user that was found by the first part of the traversal
the traversal could emit more than just the leafs
select('UsersList1','UsersList2') creates pairs of users
values('petitions') tries to access the property petitions of each pair, this will always fail
The correct approach would be:
g.V().has('User', 'UserId', within('001','002')).fold().
union(unfold(),
V().has('Group','GroupId','G001').
repeat(out()).until(hasLabel('User'))).
dedup().
values('petitions').sum()
I didn't test it, but I think the following will do:
g.V().union(
hasLabel('Group').has('GroupId','G001').repeat(
outE().inV()
).until(hasLabel('User')),
has('UserId', within('001','002')))
.dedup().values('petitions').sum()
In order to get only the tree leaves, it is better to use until. Using emit will output all inner tree nodes as well.
union merges the two inner traversals.
In Neo4j, how can I merge all nodes by a single property i.e. node1.property1=node2.property2? Or, how can I merge all nodes that have the same label name?
In the manual, it talks about this for individual nodes:
MATCH (person:Person)
MERGE (city:City { name: person.bornIn })
RETURN person.name, person.bornIn, city
Three nodes labeled City are created, each of which contains a name
property with the value of New York, Ohio, and New Jersey,
respectively. Note that even though the MATCH clause results in three
bound nodes having the value New York for the bornIn property, only a
single New York node (i.e. a City node with a name of New York) is
created. As the New York node is not matched for the first bound node,
it is created. However, the newly-created New York node is matched and
bound for the second and third bound nodes.
Result
5 rows
Nodes created: 3
Properties set: 3
Labels added: 3
My problem is that my node labels are variable and so I would have to do the above code for every node that contains a different label (the label in the above example is Person). For my example, if nodes have the property value , they will also have the same label.
UPDATE:
So, now I'm not sure my original question is what I need after all (I will clean up the question once things come into focus better).
My problem is that I have two node-edge-node instances
(node1) -[relation1]-> (node2)
and
(node2) -[relation2]->(node3)
where node1, node2, etc. are the labels for each node-edge-node. Note, node2 may have some different property values across different instances and there may be many nodes with label node2, each having exactly one relationship as shown above. Some properties will always be the same (unique identifiers related to the label name) though.
With that said, I'd like to run the query:
MATCH (n1: node1) -[r1: relation1]->
(n2: node2) -[r2: relation2]-> (n3: node3)
RETURN n1, r1, n2, r2, n3
but since there are many nodes with label node2 but none of them are connected (or merged?), the above query returns nothing. So, how can I merge all nodes with the same label so the query works as I would like?
You can tweak the query from the manual so that it works for any node that has a label from a specified collection (e.g., ['Person', 'Foo', 'Bar']). (The query below assumes that all such nodes have name and bornIn properties.)
MATCH (person)
WHERE ANY(x IN LABELS(person) WHERE x IN ['Person', 'Foo', 'Bar'])
MERGE (city:City { name: person.bornIn })
RETURN person.name, person.bornIn, city;
The above query can be tweaked to pass the list of labels in a parameter, which is more efficient if there are multiple sets of labels.
Another way of doing the same thing, if the set of labels does not change:
MATCH (person)
WHERE person:Person OR person:Foo OR person:Bar
MERGE (city:City { name: person.bornIn })
RETURN person.name, person.bornIn, city
I'm trying to figure out how to do a preorder traversal of a Btree. I know that generally preorder traversal works like this:
preorder(node)
{
print value in node
preorder(left child)
preorder(right child)
}
What's confusing to me is how to make this work with a Btree, since in each node there are multiple values and multiple child pointers. When printing values, do all the values in the node get printed before descending into the left child?
Each node looks like this:
child1 value1 child2 value2 child3 value3 child4
Also, why would anyone want to do a preorder traversal of a Btree, since an inorder traversal is what will display the values in ascending order?
Print all the values in the current node in some defined order (which is up to you, really, though left-to-right is a sensible default) then visit each child node (again, the order is up to you).