-
Notifications
You must be signed in to change notification settings - Fork 156
Apoc usage
angrykoala edited this page Jul 5, 2022
·
44 revisions
This page documents current usage of apoc and any known alternative
Location | Procedure | File | Notes |
---|---|---|---|
Cypher Projection | runFirstColumn | src/translate/create-projection-and-params.ts |
- |
Cypher Resolver | runFirstColumn | src/schema/resolvers/field/cypher.ts |
- |
Aggregate Where | runFirstColumn | src/translate/create-aggregate-where-and-params.ts |
- |
String aggregations | runFirstColumn | src/translate/translate-aggregate.ts |
Solved in #1679 |
Field Aggregations Count | runFirstColumn | src/translate/field-aggregations/create-field-aggregation.ts |
- |
Field Aggregations Projection | runFirstColumn | src/translate/field-aggregations/create-field-aggregation.ts |
- |
Connection Projection | runFirstColumn | src/translate/create-projection-and-params.ts |
- |
Query Points | runFirstColumn | src/translate/projection/elements/create-point-element.ts |
- |
Create Element Where | runFirstColumn | src/translate/where/create-element-where-and-params.ts |
- |
Used for @cypher
directive.
Schema
type Movie {
id: ID
title: String
topActor: Actor
@cypher(
statement: """
MATCH (a:Person)-[]-(this)
RETURN a
"""
)
}
type Actor {
name: String
}
Query
{
movies {
title
topActor {
name
}
}
}
Cypher
MATCH (this:Movie)
RETURN this {
.title,
topActor: head([this_topActor IN apoc.cypher.runFirstColumn("MATCH (a:Person)-[]-(this)
RETURN a", {this: this}, false) | this_topActor { .name }])
} as this
MATCH(m:Movie)
CALL {
WITH m
WITH m as this
MATCH (a:Person)-[]-(this)
RETURN a
}
WITH m, collect(a) as projection
RETURN m {.title, topActor: head([this_topActor IN projection | this_topActor { .name }]) }
- Return multiple items in an array vs a single by using
head
in the projection. - We need to keep track of subqueries for projection.
Use for aggregation where (e.g. count)
Schema
type User {
name: String!
}
type Post {
content: String!
likes: [User!]! @relationship(type: "LIKES", direction: IN)
}
Query
{
posts(where: { likesAggregate: { count: 10 } }) {
content
}
}
Cypher
MATCH (this:Post)
WHERE apoc.cypher.runFirstColumn(" MATCH (this)<-[this_likesAggregate_edge:LIKES]-(this_likesAggregate_node:User)
RETURN count(this_likesAggregate_node) = $this_likesAggregate_count
", { this: this, this_likesAggregate_count: $this_likesAggregate_count }, false )
RETURN this { .content } as this
MATCH(this:Post)
CALL {
WITH this
MATCH(this)<-[:LIKES]-(u:User)
RETURN count(u) as agg_count
}
WITH *
WHERE agg_count=10
RETURN m {.title} as this
- Keep track of subqueries for where statement.
Aggregations use first column for string returns in aggregation
Schema
type Movie {
title: String!
}
Query
{
moviesAggregate {
title {
shortest
}
}
}
Cypher
MATCH (this:Movie)
RETURN { title: { shortest:
reduce(shortest = collect(this.title)[0], current IN collect(this.title) | apoc.cypher.runFirstColumn("
RETURN
CASE size(current) < size(shortest)
WHEN true THEN current
ELSE shortest
END AS result
", { current: current, shortest: shortest }, false))
}
}
MATCH (this:Movie)
RETURN { title: { shortest:
reduce(shortest = collect(this.title)[0], current IN collect(this.title) |
CASE size(current) < size(shortest)
WHEN true THEN current
ELSE shortest
END
)
}} as this
Field aggregations use runInColumn for count values
Schema
type Movie {
title: String
actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN)
released: DateTime
}
type Actor {
name: String
age: Int
movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
}
Query
query {
movies {
title
actorsAggregate {
count
}
}
}
Cypher
MATCH (this:Movie)
RETURN this { .title,
actorsAggregate: {
count: head(apoc.cypher.runFirstColumn("MATCH (this)<-[r:ACTED_IN]-(n:Person) RETURN COUNT(n)", { this: this }))
}
} as this
MATCH (this:Movie)
CALL {
WITH this
MATCH (this)<-[r:ACTED_IN]-(n:Person)
RETURN COUNT(n) as person_count
}
WITH *
RETURN this { .title,
actorsAggregate: {
count: person_count
}
} as this
Field aggregation subquery is projected through runFirstColumn
Schema
type Movie {
title: String
actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN)
}
type Actor {
name: String
age: Int
movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
}
Query
query {
movies {
actorsAggregate {
node {
age {
min
max
average
sum
}
}
}
}
}
Cypher
MATCH (this:Movie)
RETURN this { actorsAggregate: { node: { age: head(apoc.cypher.runFirstColumn("MATCH (this)<-[r:ACTED_IN]-(n:Person)
RETURN {min: min(n.age), max: max(n.age), average: avg(n.age), sum: sum(n.age)}", { this: this })) } } } as this
MATCH (this:Movie)
CALL {
WITH this
MATCH(this)<-[r:ACTED_IN]-(n:Person)
RETURN {min: min(n.age), max: max(n.age), average: avg(n.age), sum: sum(n.age)} AS agg_data
}
WITH *
RETURN this { actorsAggregate: { node: agg_data } } as this
Schema
type PointContainer {
point: Point
}
Query
{
pointContainers(where: { point: { longitude: 1.0, latitude: 2.0 } }) {
point {
longitude
latitude
crs
}
}
}
Cypher
MATCH (this:PointContainer)
WHERE this.point = point($this_point)
RETURN this { point: apoc.cypher.runFirstColumn('RETURN
CASE this.point IS NOT NULL
WHEN true THEN { point: this.point, crs: this.point.crs }
ELSE NULL
END AS result',{ this: this },false)
} as this
MATCH(this:PointContainer)
WITH this,
CASE this.point IS NOT NULL
WHEN true THEN {point: this.point, crs: this.point.crs}
ELSE NULL
END AS this_point
RETURN this {.name, point: this_point} as this
- We need to keep track of subqueries for projection.
WIP