Last active
October 25, 2017 23:22
-
-
Save verdverm/b43444063995a7f5b913 to your computer and use it in GitHub Desktop.
neo4j / neoism example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"github.com/jmcvetta/neoism" | |
"github.com/verdverm/neo4j-tutorials/common/reset" | |
) | |
var ( | |
db *neoism.Database | |
) | |
func panicErr(err error) { | |
if err != nil { | |
panic(err) | |
} | |
} | |
func resetDB() { | |
reset.RemoveNeo4jDB() | |
reset.StartNeo4jDB() | |
} | |
func init() { | |
resetDB() | |
var err error | |
db, err = neoism.Connect("http://localhost:7474/db/data") | |
if err != nil { | |
panic(err) | |
} | |
} | |
func main() { | |
createNode() | |
queryNode() | |
createMovie() | |
createUnique() | |
setNodeProperty() | |
queryMovies() | |
queryAllNodes() | |
} | |
// Create a node with neoism function | |
func createNode() { | |
actor := "Tom Hanks" | |
// Create a node | |
n, err := db.CreateNode(neoism.Props{"name": actor}) | |
if err != nil { | |
panic(err) | |
} | |
// Add a label | |
n.AddLabel("Actor") | |
fmt.Println("createNode()", n.Data) | |
} | |
func queryNode() { | |
// query statemunt | |
stmt := ` | |
MATCH (actor:Actor) | |
WHERE actor.name = {actorSub} | |
RETURN actor | |
` | |
// query params | |
actor := "Tom Hanks" | |
params := neoism.Props{"actorSub": actor} | |
// query results | |
res := []struct { | |
Actor neoism.Node | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
Parameters: params, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
// check results | |
if len(res) != 1 { | |
panic(fmt.Sprintf("Incorrect results len in query1()\n\tgot %d, expected 1\n", len(res))) | |
} | |
n := res[0].Actor // Only one row of data returned | |
fmt.Printf("queryNode() -> %+v\n", n.Data) | |
} | |
func createMovie() { | |
actor := "Tom Hanks" | |
movie := "Sleepless in Seattle" | |
// query statemunt | |
stmt := ` | |
MATCH (actor:Actor) | |
WHERE actor.name = {actorSub} | |
CREATE (movie:Movie {title: {movieSub}}) | |
CREATE (actor)-[:ACTED_IN]->(movie); | |
` | |
// query params | |
params := neoism.Props{ | |
"actorSub": actor, | |
"movieSub": movie, | |
} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
Parameters: params, | |
Result: nil, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
fmt.Println("createMovie()") | |
} | |
func createUnique() { | |
actor := "Tom Hanks" | |
movie := "Forrest Gump" | |
// query statemunt | |
stmt := ` | |
MATCH (actor:Actor {name: {actorSub}}) | |
CREATE UNIQUE (actor)-[r:ACTED_IN]->(movie:Movie {title: {movieSub}}) | |
RETURN r; | |
` | |
// query params | |
params := neoism.Props{ | |
"actorSub": actor, | |
"movieSub": movie, | |
} | |
// query results | |
res := []struct { | |
A string `json:"a.name"` // `json` tag matches column name in query | |
Rel string `json:"type(r)"` | |
B string `json:"b.name"` | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
Parameters: params, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
r := res[0] | |
fmt.Println("createUnique()", r.A, r.Rel, r.B) | |
} | |
func setNodeProperty() { | |
actor := "Tom Hanks" | |
dob := 1944 | |
// query statemunt | |
stmt := ` | |
MATCH (actor:Actor {name: {actorSub}}) | |
SET actor.DoB = {dobSub} | |
RETURN actor.name, actor.DoB; | |
` | |
// query params | |
params := neoism.Props{ | |
"actorSub": actor, | |
"dobSub": dob, | |
} | |
// query results | |
res := []struct { | |
Name string `json:"actor.name"` // `json` tag matches column name in query | |
DoB string `json:"actor.DoB"` | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
Parameters: params, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
r := res[0] | |
fmt.Println("setNodeProperty()", r.Name, r.DoB) | |
} | |
func queryMovies() { | |
// query statemunt | |
stmt := ` | |
MATCH (movie:Movie) | |
RETURN movie; | |
` | |
// query params | |
actor := "Tom Hanks" | |
params := neoism.Props{"actorSub": actor} | |
// query results | |
res := []struct { | |
Movie neoism.Node | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
Parameters: params, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
// check results | |
if len(res) != 2 { | |
panic(fmt.Sprintf("Incorrect results len in query1()\n\tgot %d, expected 2\n", len(res))) | |
} | |
fmt.Printf("queryMovies()\n") | |
for i, _ := range res { | |
n := res[i].Movie // Only one row of data returned | |
fmt.Printf(" Node[%d] %+v\n", i, n.Data) | |
} | |
} | |
func queryAllNodes() { | |
// query results | |
res := []struct { | |
N neoism.Node // Column "n" gets automagically unmarshalled into field N | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: "MATCH (n) RETURN n", | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
fmt.Printf("queryAllNodes(%d)\n", len(res)) | |
for i, _ := range res { | |
n := res[i].N // Only one row of data returned | |
fmt.Printf(" Node[%d] %+v\n", i, n.Data) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"github.com/jmcvetta/neoism" | |
"github.com/verdverm/neo4j-tutorials/common/reset" | |
) | |
var ( | |
db *neoism.Database | |
) | |
func panicErr(err error) { | |
if err != nil { | |
panic(err) | |
} | |
} | |
func init() { | |
resetDB() | |
var err error | |
db, err = neoism.Connect("http://localhost:7474/db/data") | |
if err != nil { | |
panic(err) | |
} | |
initDB() | |
} | |
func resetDB() { | |
reset.RemoveNeo4jDB() | |
reset.StartNeo4jDB() | |
} | |
func initDB() { | |
stmt := ` | |
CREATE (matrix1:Movie { title : 'The Matrix', year : '1999-03-31' }) | |
CREATE (matrix2:Movie { title : 'The Matrix Reloaded', year : '2003-05-07' }) | |
CREATE (matrix3:Movie { title : 'The Matrix Revolutions', year : '2003-10-27' }) | |
CREATE (keanu:Actor { name:'Keanu Reeves' }) | |
CREATE (laurence:Actor { name:'Laurence Fishburne' }) | |
CREATE (carrieanne:Actor { name:'Carrie-Anne Moss' }) | |
CREATE (keanu)-[:ACTS_IN { role : 'Neo' }]->(matrix1) | |
CREATE (keanu)-[:ACTS_IN { role : 'Neo' }]->(matrix2) | |
CREATE (keanu)-[:ACTS_IN { role : 'Neo' }]->(matrix3) | |
CREATE (laurence)-[:ACTS_IN { role : 'Morpheus' }]->(matrix1) | |
CREATE (laurence)-[:ACTS_IN { role : 'Morpheus' }]->(matrix2) | |
CREATE (laurence)-[:ACTS_IN { role : 'Morpheus' }]->(matrix3) | |
CREATE (carrieanne)-[:ACTS_IN { role : 'Trinity' }]->(matrix1) | |
CREATE (carrieanne)-[:ACTS_IN { role : 'Trinity' }]->(matrix2) | |
CREATE (carrieanne)-[:ACTS_IN { role : 'Trinity' }]->(matrix3) | |
` | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
} | |
err := db.Cypher(&cq) | |
panicErr(err) | |
listGraphData() | |
} | |
func main() { | |
getOtherMoviesViaActors("The Matrix") | |
getCoActingFromMovie("The Matrix") | |
getActorPaths("Keanu Reeves", "Carrie-Anne Moss") | |
} | |
func getOtherMoviesViaActors(movie string) { | |
stmt := ` | |
MATCH (:Movie { title: {movieSub} })<-[:ACTS_IN]-(actor)-[:ACTS_IN]->(movie) | |
RETURN movie.title AS Title, collect(actor.name) AS Actors, count(*) AS Count | |
ORDER BY count(*) DESC ; | |
` | |
params := neoism.Props{"movieSub": movie} | |
// query results | |
res := []struct { | |
Title string | |
Actors []string | |
Count int | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
Parameters: params, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
fmt.Println("Movies: ", movie, len(res)) | |
for i, _ := range res { | |
n := res[i] | |
fmt.Printf(" [%d] %24q %d %v\n", i, n.Title, n.Count, n.Actors) | |
} | |
} | |
func getCoActingFromMovie(movie string) { | |
stmt := ` | |
MATCH (:Movie { title: {movieSub} })<-[:ACTS_IN]-(actor)-[:ACTS_IN]->(movie)<-[:ACTS_IN]-(colleague) | |
RETURN actor.name AS Actor, collect(DISTINCT colleague.name) AS Actors; | |
` | |
params := neoism.Props{"movieSub": movie} | |
// query results | |
res := []struct { | |
Actor string | |
Actors []string | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
Parameters: params, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
fmt.Println("Movies: ", movie, len(res)) | |
for i, _ := range res { | |
n := res[i] | |
fmt.Printf(" [%d] %24q %v\n", i, n.Actor, n.Actors) | |
} | |
} | |
func getActorPaths(actor1, actor2 string) { | |
stmt := ` | |
MATCH p =(:Actor { name: {actor1Sub} })-[:ACTS_IN*0..5]-(:Actor { name: {actor2Sub} }) | |
RETURN extract(n IN nodes(p)| coalesce(n.title,n.name)) AS List, length(p) AS Len | |
ORDER BY length(p) | |
LIMIT 10; | |
` | |
params := neoism.Props{"actor1Sub": actor1, "actor2Sub": actor2} | |
// query results | |
res := []struct { | |
List []string | |
Len int | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
Parameters: params, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
fmt.Println("Paths: ", actor1, actor2) | |
for i, _ := range res { | |
n := res[i] | |
fmt.Printf(" [%d] %d %v\n", i, n.Len, n.List) | |
} | |
} | |
func listGraphData() { | |
// query results | |
res := []struct { | |
From neoism.Node | |
Rel neoism.Relationship | |
To neoism.Node | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: ` | |
MATCH (n)-[r]->(m) | |
RETURN n AS From, r AS Rel, m AS To; | |
`, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
fmt.Println("Graph Data: ", len(res)) | |
for i, _ := range res { | |
n := res[i] | |
fmt.Printf(" [%d] %+v -> %+v -> %+v\n", i, n.From.Data, n.Rel.Data, n.To.Data) | |
} | |
} | |
// careful... | |
func queryNodes(MATCH, WHERE, CREATE, RETURN, ORDERBY string) []struct{ N neoism.Node } { | |
stmt := "" | |
if MATCH != "" { | |
stmt += "MATCH " + MATCH + " " | |
} | |
if WHERE != "" { | |
stmt += "WHERE " + WHERE + " " | |
} | |
if CREATE != "" { | |
stmt += "CREATE " + CREATE + " " | |
} | |
if RETURN != "" { | |
stmt += "RETURN " + RETURN + " " | |
} | |
if ORDERBY != "" { | |
stmt += "ORDERBY " + ORDERBY + " " | |
} | |
stmt += ";" | |
// params | |
params := neoism.Props{ | |
"MATCH": MATCH, | |
"WHERE": WHERE, | |
"CREATE": CREATE, | |
"RETURN": RETURN, | |
"ORDERBY": ORDERBY, | |
} | |
// query results | |
res := []struct { | |
N neoism.Node | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
Parameters: params, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
return res | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"github.com/jmcvetta/neoism" | |
"github.com/verdverm/neo4j-tutorials/common/reset" | |
) | |
var ( | |
db *neoism.Database | |
) | |
func panicErr(err error) { | |
if err != nil { | |
panic(err) | |
} | |
} | |
func resetDB() { | |
reset.RemoveNeo4jDB() | |
reset.StartNeo4jDB() | |
} | |
func initDB() { | |
stmt := ` | |
CREATE (matrix1:Movie { title : 'The Matrix', year : '1999-03-31' }) | |
CREATE (matrix2:Movie { title : 'The Matrix Reloaded', year : '2003-05-07' }) | |
CREATE (matrix3:Movie { title : 'The Matrix Revolutions', year : '2003-10-27' }) | |
CREATE (keanu:Actor { name:'Keanu Reeves' }) | |
CREATE (laurence:Actor { name:'Laurence Fishburne' }) | |
CREATE (carrieanne:Actor { name:'Carrie-Anne Moss' }) | |
CREATE (keanu)-[:ACTS_IN { role : 'Neo' }]->(matrix1) | |
CREATE (keanu)-[:ACTS_IN { role : 'Neo' }]->(matrix2) | |
CREATE (keanu)-[:ACTS_IN { role : 'Neo' }]->(matrix3) | |
CREATE (laurence)-[:ACTS_IN { role : 'Morpheus' }]->(matrix1) | |
CREATE (laurence)-[:ACTS_IN { role : 'Morpheus' }]->(matrix2) | |
CREATE (laurence)-[:ACTS_IN { role : 'Morpheus' }]->(matrix3) | |
CREATE (carrieanne)-[:ACTS_IN { role : 'Trinity' }]->(matrix1) | |
CREATE (carrieanne)-[:ACTS_IN { role : 'Trinity' }]->(matrix2) | |
CREATE (carrieanne)-[:ACTS_IN { role : 'Trinity' }]->(matrix3) | |
` | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
} | |
func init() { | |
// resetDB() | |
var err error | |
db, err = neoism.Connect("http://localhost:7474/db/data") | |
if err != nil { | |
panic(err) | |
} | |
// initDB() | |
} | |
func main() { | |
countNodes() | |
showAllActors() | |
getActorByName("Laurence Fishburne") | |
showAllMovies() | |
getMovieByName("The Matrix") | |
listGraphData() | |
} | |
// Create a node with neoism function | |
func countNodes() { | |
res := queryNodes("(n)", "", "", "n", "") | |
fmt.Println("countNodes()", len(res)) | |
} | |
func showAllActors() { | |
res := queryNodes("(n:Actor)", "", "", "n", "") | |
fmt.Println("Actors: ", len(res)) | |
for i, _ := range res { | |
n := res[i].N // Only one row of data returned | |
fmt.Printf(" Actor[%d] %+v\n", i, n.Data) | |
} | |
} | |
func getActorByName(name string) { | |
res := queryNodes("(n:Actor)", "n.name = '"+name+"'", "", "n", "") | |
fmt.Println("Actors: ", len(res)) | |
for i, _ := range res { | |
n := res[i].N // Only one row of data returned | |
fmt.Printf(" Actor[%d] %+v\n", i, n.Data) | |
} | |
} | |
func showAllMovies() { | |
res := queryNodes("(n:Movie)", "", "", "n", "") | |
fmt.Println("Movies: ", len(res)) | |
for i, _ := range res { | |
n := res[i].N // Only one row of data returned | |
fmt.Printf(" Movie[%d] %+v\n", i, n.Data) | |
} | |
} | |
func getMovieByName(title string) { | |
res := queryNodes("(n:Movie)", "n.title = '"+title+"'", "", "n", "") | |
fmt.Println("Actors: ", len(res)) | |
for i, _ := range res { | |
n := res[i].N // Only one row of data returned | |
fmt.Printf(" Actor[%d] %+v\n", i, n.Data) | |
} | |
} | |
func listGraphData() { | |
// query results | |
res := []struct { | |
From neoism.Node | |
Rel neoism.Relationship | |
To neoism.Node | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: ` | |
MATCH (n)-[r]->(m) | |
RETURN n AS From, r AS Rel, m AS To; | |
`, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
fmt.Println("Graph Data: ", len(res)) | |
for i, _ := range res { | |
n := res[i] // Only one row of data returned | |
fmt.Printf(" [%d] %+v -> %+v -> %+v\n", i, n.From.Data, n.Rel.Data, n.To.Data) | |
} | |
} | |
// careful... | |
func queryNodes(MATCH, WHERE, CREATE, RETURN, ORDERBY string) []struct{ N neoism.Node } { | |
stmt := "" | |
if MATCH != "" { | |
stmt += "MATCH " + MATCH + " " | |
} | |
if WHERE != "" { | |
stmt += "WHERE " + WHERE + " " | |
} | |
if CREATE != "" { | |
stmt += "CREATE " + CREATE + " " | |
} | |
if RETURN != "" { | |
stmt += "RETURN " + RETURN + " " | |
} | |
if ORDERBY != "" { | |
stmt += "ORDERBY " + ORDERBY + " " | |
} | |
stmt += ";" | |
// params | |
params := neoism.Props{ | |
"MATCH": MATCH, | |
"WHERE": WHERE, | |
"CREATE": CREATE, | |
"RETURN": RETURN, | |
"ORDERBY": ORDERBY, | |
} | |
// query results | |
res := []struct { | |
N neoism.Node // Column "n" gets automagically unmarshalled into field N | |
}{} | |
// construct query | |
cq := neoism.CypherQuery{ | |
Statement: stmt, | |
Parameters: params, | |
Result: &res, | |
} | |
// execute query | |
err := db.Cypher(&cq) | |
panicErr(err) | |
return res | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package reset | |
import ( | |
"fmt" | |
"time" | |
"github.com/fsouza/go-dockerclient" | |
) | |
func panicErr(err error) { | |
if err != nil { | |
panic(err) | |
} | |
} | |
var endpoint = "unix:///var/run/docker.sock" | |
// Restarts the tpires/Neo4j docker container | |
// docker run -d --privileged -p 7474:7474 tpires/neo4j --name neo4j | |
func RemoveNeo4jDB() { | |
// docker server URL | |
// remove options | |
ropts := docker.RemoveContainerOptions{ | |
ID: "neo4j", | |
RemoveVolumes: true, | |
Force: true, | |
} | |
client, err := docker.NewClient(endpoint) | |
panicErr(err) | |
fmt.Println("Removing Neo4j container") | |
err = client.RemoveContainer(ropts) | |
panicErr(err) | |
} | |
func StartNeo4jDB() { | |
// create options | |
copts := docker.CreateContainerOptions{ | |
Name: "neo4j", | |
Config: &docker.Config{ | |
Image: "tpires/neo4j", | |
ExposedPorts: map[docker.Port]struct{}{ | |
docker.Port("7474"): {}, | |
}, | |
}, | |
} | |
// start options for: | |
sopts := &docker.HostConfig{ | |
ContainerIDFile: "tpires/neo4j", | |
Privileged: true, | |
PortBindings: map[docker.Port][]docker.PortBinding{ | |
docker.Port("7474"): { | |
docker.PortBinding{ | |
HostIp: "0.0.0.0", | |
HostPort: "7474", | |
}, | |
}, | |
}, | |
} | |
client, err := docker.NewClient(endpoint) | |
panicErr(err) | |
fmt.Println("Creating Neo4j container") | |
_, err = client.CreateContainer(copts) | |
panicErr(err) | |
fmt.Println("Starting Neo4j container") | |
err = client.StartContainer("neo4j", sopts) | |
panicErr(err) | |
fmt.Println("Sleeping 10s") | |
time.Sleep(10 * time.Second) | |
fmt.Println("Successfully restarted Neo4j\n") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment