Is there any way to select specific tree roots with their descendants? - typeorm

Problem (Hypothetical scenario)
I have two entities: House and Person. Each House has an array of people that lives in there, and each Person can have children (as an array of Person), a parent (a Person too, naturally) and a House.
Person is a Tree Entity. How can I select a house with the people in a tree structure?
What I've tried
houseRepo.find({ relations: ['people'] })
This gives me an array of House, each having an flat array of the people that lives in the house.
(If there is no other way, I will use this approach and change the array into a tree structure array manually.)
I've tried to use the function that typeorm uses to set the relations between the objects, but unfortunately I can't just import/require it.
(That's it for now)
Code
House Entity:
#Entity()
export class House {
#PrimaryGeneratedColumn()
id: number;
#OneToMany(type => Person, p => p.house)
people: Person[];
}
Person Entity:
#Entity()
#Tree('closure-table')
export class Person {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#TreeParent()
parent: Person;
#TreeChildren()
children: Person[];
#ManyToOne(type => House, h => h.people)
house: House;
}
What I expect
// House object
{
"id": 1,
// People living in the house, in a tree structure
"people": [
{
"id": 1,
"name": "Parent 1",
"children": [
{
"id": 2,
"name": "Child 1"
},
{
"id": 3,
"name": "Child 2"
},
]
},
{
"id": 4,
"name": "Parent 2",
"children": [
{
"id": 5,
"name": "Child 1"
},
{
"id": 6,
"name": "Child 2"
}
]
},
]
}

If you are using the tree decorators, note down that you need to use "tree repositories" as explained in the docs, because right now you are using a usual repository.
So, mostly what you want is:
const manager = getManager();
const trees = await manager.getTreeRepository(House).findTrees();

Related

Neo4j recursive cypher query resulting in nested JSON structure

I am trying to figure out cypher query in order to get nested JSON structure as a result. Below I present an example of the graph.
MATCH (user:User {name:"User_1"})
OPTIONAL MATCH (user)-[rel*]->(subUser:User)
RETURN *
Query above allows me to get all the nodes and relationships required to transform everything to JSON structure I want but that requires me to process everything after getting the result from querying the database. To achieve that I need to match identity of nodes and relationship in order to get the nested JSON.
I was wondering if it is possible to achieve that directly from building cypher query.
Important thing is that we do not know how many levels of "child" Users we have starting from User_1
Expected JSON structure:
{
"user": "User_1",
"children": [
{
"user": "User_2",
"children": [
{
"user": "User_5",
"children": []
}
]
},{
"user": "User_3",
"children": [
{
"user": "User_6",
"children": []
}
]
},{
"user": "User_4",
"children": []
}
]
}
Is it possible?
As suggested in the comments by #nimrod serok, you can use the apoc.convert.toTree method, it will give you the tree-structured JSON, as desired, with one caveat, the keys of the JSON will be different. For the data:
MERGE (u1:User{name: 'User1'})
MERGE (u2:User{name: 'User2'})
MERGE (u3:User{name: 'User3'})
MERGE (u4:User{name: 'User4'})
MERGE (u5:User{name: 'User5'})
MERGE (u6:User{name: 'User6'})
MERGE (u1)-[:POINTS]->(u2)-[:POINTS]->(u5)
MERGE (u1)-[:POINTS]->(u3)-[:POINTS]->(u6)
MERGE (u1)-[:POINTS]->(u4)
The query:
MATCH (user:User {name:"User1"})
OPTIONAL MATCH path = (user)-[:POINTS*]->(subUser:User)
WITH collect(path) AS paths
CALL apoc.convert.toTree(paths, true, {nodes: {User: ['name']}})
YIELD value
RETURN value
produces the output:
{
"_type": "User",
"name": "User1",
"_id": 4,
"points": [
{
"_type": "User",
"name": "User3",
"_id": 6,
"points": [
{
"_type": "User",
"name": "User6",
"_id": 9
}
]
},
{
"_type": "User",
"name": "User2",
"_id": 5,
"points": [
{
"_type": "User",
"name": "User5",
"_id": 8
}
]
},
{
"_type": "User",
"name": "User4",
"_id": 7
}
]
}
as you can see, the relationship type POINTS, comes in place of children, and the key name comes for the user name. The other fields _type and _id can be ignored.
apoc.convert.toTree() is certainly the best answer for the question you asked.
If one is interested in a text output then ORDPATH would be another solution. ORDPATH is a concatenated bitstring which sorts in hierarchical order. More on this at this link. A Neo4j user defined function implementing this is at GitHub.

How to use ORDER BY and LIMIT on node children but not their parents? Cypher

I have a set of Author nodes. An Author node is the single parent of multiple Book nodes.
My goal: To print all Author nodes with no order and no limit, with each authors' first three books in alphabetical order.
Desired output: (let's pretend book names are a single letter)
[
{
"name" : "Leo Tolstoy",
"books": [
{ "name": "A" },
{ "name": "B" },
{ "name": "D" }
]
},
{
"name": "Charles Dickens",
"books": [
{ "name": "C" },
{ "name": "E" },
{ "name": "F" }
]
},
{
"name": "Oscar Wilde
...
]
My Problem:
I tried this:
MATCH(author:Author)
WITH author
OPTIONAL MATCH(author)-[:WROTE]->(book:Book)
WITH author, book
ORDER BY book.name
LIMIT 3
WITH author, collect(book) AS books
RETURN collect (
{
name: author.name,
books: books
}
);
But this gives:
[
{
"name" : "Leo Tolstoy",
"books": [
{ "name": "A" },
{ "name": "B" },
]
},
{
"name": "Charles Dickens",
"books": [
{ "name": "C" }
]
}
]
How could I achieve my desired output in Neo4j v3.5?
[EDITED]
This should work:
MATCH(author:Author)
OPTIONAL MATCH(author)-[:WROTE]->(book:Book)
WITH author, book.name AS bookName
ORDER BY bookName
WITH author, COLLECT({name: bookName})[..3] AS bookNames
RETURN COLLECT({name: author.name, books: bookNames}) AS result

How to query Neo4j nodes and the relationship between the nodes?

Now I have a graph like this:
Then I want to query the nodes which the "SGJ" "HAVE"
MATCH (n:User) -[R:MASTER]-> (k:KNode)
WHERE n.username={username}
RETURN k
But I get the result like this:
{
"id": 360,
"children": null,
"name": "Arrays",
"intro": "this is an intro"
},
{
"id": 300,
"children": null,
"name": "Java",
"intro": "this is an intro"
}
The relationship between these nodes just gone, I hope I can query the nodes with the relationship remain like:
{
"id": 360,
"children": [
{
"id": 300,
"children": null,
"name": "Java",
"intro": "this is an intro"
}
],
"name": "Arrays",
"intro": "this is an intro"
}
Here's the entity definition:
#Data
#NodeEntity
public class KNode {
#GraphId
Long id;
#Relationship(type = "BELONGS_TO", direction = Relationship.INCOMING)
List<KNode> children;
private String name;
private String intro;
}
Is there any solution? Thanks.
You are just returning a node instead of path. Try one of these requests to return also the children and relationship :
MATCH (n:User) -[R:MASTER]-> (k:KNode)
WHERE n.username={username}
OPIONAL MATCH p=(k)-[r]-(c)
RETURN p
Or :
MATCH (n:User) -[R:MASTER]-> (k:KNode)
WHERE n.username={username}
WITH k
MATCH p=(k)-[r]-(c)
RETURN p

How to print a JSON-structure from User models hierarchy

I am building an Rails 5 app and in this app I got a User model. Each user can have exactly one manager (using the attribute manager_id).
I want to print a JSON-structure (using Rabl) that shows how the User models are related. Meaning I want to print out how is manager to each user.
User 1 (manager_id is null)
|
User 2 (manager_id is 1)
User 3 (manager_id is 1)
|
User 4 (manager_id is 3)
This is what I want the UI to look like (this is already working I just need the JSON-structure to support it).
These is how the finished structure must look like.
datasource =
'name': 'Peter Fettingview'
'title': 'CEO'
'children': [
{
'name': 'Mike Palmer'
'title': 'CIO'
}
{
'name': 'Maria Persson'
'title': 'CTO'
'children': [
{
'name': 'James Hatton'
'title': 'Customer success'
}
{
'name': 'Lars Andersson'
'title': 'Customer success'
}
]
}
{
'name': 'Jan Roslund'
'title': 'Economy'
}
{
'name': 'Annika Holm'
'title': 'Sales'
}
]
This is what I got right now
attributes :id, :fullname
node :children do |n|
n.children.map { |c| partial("admin/users/index", :object => c) }
end
This is the output
[{
"id": 1,
"fullname": "Peter Fettingview",
"children": [{
"id": 2,
"fullname": "Richard Pooler"
},
{
"id": 1,
"fullname": "Mike Palmer"
}
]
},
{
"id": 2,
"fullname": "Richard Pooler",
"children": [{
"id": 3,
"fullname": "Mike Palmer"
}]
},
{
"id": 3,
"fullname": "Mike Palmer",
"children": []
}
]
How can I print out such a JSON-tree using the User models?
I have had to use tree data structures (i.e. self-referential models) before. I would consider using the Ancestry gem. It allows you to do things like enumerate descendants and paths bath to the root, making traversing your data structure significantly easier.

Get associations when doing Get request

I am working on ruby on rails as my API with mongoid. Suppose I have 2 models:
class Human
field: salary, type: Integer
has_many: dogs
end
class Dog
field: name, type: String
belongs_to: human
end
I want to get all dogs that human has when I query all humans, how do I do this?
I know embedded documents can do this, but then I cannot find dog document easily. That is why I use association rather than embedded document.
Expected output when I query all human:
[
{
"_id": "1",
"salary": 5000,
"dogs": [
{
"_id": "1",
"name": "dog1",
}
]
},
{
"_id": "2",
"salary": 8000,
"dogs": [
{
"_id": "2",
"name": "dog2",
},
{
"_id": "3",
"name": "dog3",
}
]
}
]
Thanks in advance. I am very new on this and sorry if I asked some stupid questions.
humans = Human.includes(:dog)
humans consists of the required data with each individual containing the dogs they own with details such as their name.

Resources