├── go.mod ├── go.sum ├── Dockerfile ├── db.go ├── docker-compose.yml ├── delete_user.go ├── get_friends.go ├── create_user.go ├── main.go ├── LICENSE ├── create_freindship.go ├── find_mutal_friends.go ├── recommend_friends.go └── README.md /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mahdi-eth/neo4j-social-network 2 | 3 | go 1.23.1 4 | 5 | require github.com/neo4j/neo4j-go-driver/v5 v5.24.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/neo4j/neo4j-go-driver/v5 v5.24.0 h1:7MAFoB7L6f9heQUo/tJ5EnrrpVzm9ZBHgH8ew03h6Eo= 2 | github.com/neo4j/neo4j-go-driver/v5 v5.24.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k= 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.23.1 as build 2 | 3 | WORKDIR /app 4 | 5 | COPY go.mod go.sum ./ 6 | 7 | RUN go mod download 8 | 9 | COPY . . 10 | 11 | RUN go build -o main . 12 | 13 | EXPOSE 8080 14 | 15 | CMD ["./main"] -------------------------------------------------------------------------------- /db.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/neo4j/neo4j-go-driver/v5/neo4j" 7 | ) 8 | 9 | func connectToNeo4j() neo4j.DriverWithContext { 10 | uri := "neo4j://neo4j:7687" 11 | username := "neo4j" 12 | password := "test1234" 13 | 14 | driver, err := neo4j.NewDriverWithContext(uri, neo4j.BasicAuth(username, password, "")) 15 | if err != nil { 16 | log.Fatal("Error connecting to Neo4j:", err) 17 | } 18 | return driver 19 | } -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | neo4j: 5 | image: neo4j:5.10 6 | container_name: neo4j 7 | environment: 8 | - NEO4J_AUTH=neo4j/test1234 9 | ports: 10 | - "7474:7474" 11 | - "7687:7687" 12 | volumes: 13 | - neo4j_data:/data 14 | - neo4j_logs:/logs 15 | networks: 16 | - app-network 17 | 18 | go-app: 19 | build: 20 | context: . 21 | dockerfile: Dockerfile 22 | container_name: go-app 23 | depends_on: 24 | - neo4j 25 | environment: 26 | - NEO4J_URI=bolt://neo4j:7687 27 | - NEO4J_USERNAME=neo4j 28 | - NEO4J_PASSWORD=test1234 29 | networks: 30 | - app-network 31 | 32 | networks: 33 | app-network: 34 | driver: bridge 35 | 36 | volumes: 37 | neo4j_data: 38 | neo4j_logs: 39 | -------------------------------------------------------------------------------- /delete_user.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/neo4j/neo4j-go-driver/v5/neo4j" 7 | ) 8 | 9 | // Delete a user and their relationships 10 | func deleteUser(driver neo4j.DriverWithContext, username string) error { 11 | session := driver.NewSession(context.Background(), neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) 12 | defer session.Close(context.Background()) 13 | 14 | _, err := session.ExecuteWrite(context.Background(), func(tx neo4j.ManagedTransaction) (interface{}, error) { 15 | query := ` 16 | MATCH (u:User {name: $username}) 17 | DETACH DELETE u 18 | ` 19 | params := map[string]interface{}{ 20 | "username": username, 21 | } 22 | _, err := tx.Run(context.Background(), query, params) 23 | return nil, err 24 | }) 25 | 26 | return err 27 | } 28 | -------------------------------------------------------------------------------- /get_friends.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/neo4j/neo4j-go-driver/v5/neo4j" 8 | ) 9 | 10 | func getFriends(driver neo4j.DriverWithContext, user string) error { 11 | session := driver.NewSession(context.Background(), neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) 12 | defer session.Close(context.Background()) 13 | 14 | _, err := session.ExecuteRead(context.Background(), func(tx neo4j.ManagedTransaction) (interface{}, error) { 15 | query := ` 16 | MATCH (u:User {name: $user})-[:FRIENDS_WITH]->(friend) 17 | RETURN friend.name 18 | ` 19 | params := map[string]interface{}{ 20 | "user": user, 21 | } 22 | result, err := tx.Run(context.Background(), query, params) 23 | if err != nil { 24 | return nil, err 25 | } 26 | for result.Next(context.Background()) { 27 | fmt.Println(user, "is friends with:", result.Record().Values[0]) 28 | } 29 | return nil, result.Err() 30 | }) 31 | return err 32 | } -------------------------------------------------------------------------------- /create_user.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/neo4j/neo4j-go-driver/v5/neo4j" 8 | ) 9 | 10 | func createUser(driver neo4j.DriverWithContext, name string, age int) error { 11 | session := driver.NewSession(context.Background(), neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) 12 | defer session.Close(context.Background()) 13 | 14 | _, err := session.ExecuteWrite(context.Background(), func(tx neo4j.ManagedTransaction) (interface{}, error) { 15 | query := ` 16 | CREATE (u:User {name: $name, age: $age}) 17 | RETURN u 18 | ` 19 | params := map[string]interface{}{ 20 | "name": name, 21 | "age": age, 22 | } 23 | result, err := tx.Run(context.Background(), query, params) 24 | if err != nil { 25 | return nil, err 26 | } 27 | if result.Next(context.Background()) { 28 | fmt.Println("User created:", result.Record().Values[0]) 29 | } 30 | return nil, result.Err() 31 | }) 32 | return err 33 | } -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | func main() { 10 | driver := connectToNeo4j() 11 | defer driver.Close(context.Background()) 12 | 13 | createUser(driver, "Alice", 30) 14 | createUser(driver, "Bob", 25) 15 | createFriendship(driver, "Alice", "Bob") 16 | createUser(driver, "Charlie", 28) 17 | createFriendship(driver, "Bob", "Charlie") 18 | 19 | // Find mutual friends 20 | mutualFriends, err := findMutualFriends(driver, "Alice", "Bob") 21 | if err != nil { 22 | log.Fatal("Error finding mutual friends:", err) 23 | } 24 | fmt.Println("Mutual friends between Alice and Bob:", mutualFriends) 25 | 26 | // Recommend friends to Alice 27 | recommendations, err := recommendFriends(driver, "Alice") 28 | if err != nil { 29 | log.Fatal("Error recommending friends:", err) 30 | } 31 | fmt.Println("Friend recommendations for Alice:", recommendations) 32 | 33 | 34 | if err := getFriends(driver, "Alice"); err != nil { 35 | log.Fatal("Error fetching friends:", err) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Mahdi Ettehadnejad 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /create_freindship.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/neo4j/neo4j-go-driver/v5/neo4j" 8 | ) 9 | 10 | func createFriendship(driver neo4j.DriverWithContext, user1 string, user2 string) error { 11 | session := driver.NewSession(context.Background(), neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) 12 | defer session.Close(context.Background()) 13 | 14 | _, err := session.ExecuteWrite(context.Background(), func(tx neo4j.ManagedTransaction) (interface{}, error) { 15 | query := ` 16 | MATCH (u1:User {name: $user1}), (u2:User {name: $user2}) 17 | CREATE (u1)-[:FRIENDS_WITH]->(u2) 18 | RETURN u1, u2 19 | ` 20 | params := map[string]interface{}{ 21 | "user1": user1, 22 | "user2": user2, 23 | } 24 | result, err := tx.Run(context.Background(), query, params) 25 | if err != nil { 26 | return nil, err 27 | } 28 | if result.Next(context.Background()) { 29 | fmt.Println("Friendship created between", user1, "and", user2) 30 | } 31 | return nil, result.Err() 32 | }) 33 | return err 34 | } 35 | -------------------------------------------------------------------------------- /find_mutal_friends.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/neo4j/neo4j-go-driver/v5/neo4j" 7 | ) 8 | 9 | // Find mutual friends between two users 10 | func findMutualFriends(driver neo4j.DriverWithContext, user1, user2 string) ([]string, error) { 11 | session := driver.NewSession(context.Background(), neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) 12 | defer session.Close(context.Background()) 13 | 14 | friends := []string{} 15 | 16 | _, err := session.ExecuteRead(context.Background(), func(tx neo4j.ManagedTransaction) (interface{}, error) { 17 | query := ` 18 | MATCH (u1:User {name: $user1})-[:FRIENDS_WITH]-(mutualFriend)-[:FRIENDS_WITH]-(u2:User {name: $user2}) 19 | RETURN mutualFriend.name 20 | ` 21 | params := map[string]interface{}{ 22 | "user1": user1, 23 | "user2": user2, 24 | } 25 | result, err := tx.Run(context.Background(), query, params) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | for result.Next(context.Background()) { 31 | friend := result.Record().Values[0].(string) 32 | friends = append(friends, friend) 33 | } 34 | return friends, result.Err() 35 | }) 36 | 37 | if err != nil { 38 | return nil, err 39 | } 40 | return friends, nil 41 | } 42 | -------------------------------------------------------------------------------- /recommend_friends.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/neo4j/neo4j-go-driver/v5/neo4j" 7 | ) 8 | 9 | // Recommend friends to a user (friends of friends) 10 | func recommendFriends(driver neo4j.DriverWithContext, username string) ([]string, error) { 11 | session := driver.NewSession(context.Background(), neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) 12 | defer session.Close(context.Background()) 13 | 14 | recommendations := []string{} 15 | 16 | _, err := session.ExecuteRead(context.Background(), func(tx neo4j.ManagedTransaction) (interface{}, error) { 17 | query := ` 18 | MATCH (u:User {name: $username})-[:FRIENDS_WITH]-(friend)-[:FRIENDS_WITH]-(recommendedFriend) 19 | WHERE NOT (u)-[:FRIENDS_WITH]-(recommendedFriend) 20 | RETURN recommendedFriend.name 21 | ` 22 | params := map[string]interface{}{ 23 | "username": username, 24 | } 25 | result, err := tx.Run(context.Background(), query, params) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | for result.Next(context.Background()) { 31 | recommendation := result.Record().Values[0].(string) 32 | recommendations = append(recommendations, recommendation) 33 | } 34 | return recommendations, result.Err() 35 | }) 36 | 37 | if err != nil { 38 | return nil, err 39 | } 40 | return recommendations, nil 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Neo4j-social-network 2 | 3 | ## 🧑‍🤝‍🧑 A Social Network Built with Go and Neo4j Graph Database 4 | 5 | This project demonstrates how to build a simple **social network** using **Go** as the backend language and **Neo4j** as the graph database to handle relationships between users. The application includes features like mutual friend discovery, friend recommendations, and user management. The whole project is containerized using Docker, making it easy to deploy and run. 6 | 7 | --- 8 | 9 | ## 🎯 Features 10 | 11 | - **Mutual Friends**: Find mutual friends between two users. 12 | - **Friend Recommendations**: Suggest friends based on friends of friends. 13 | - **User Management**: Add, delete, and query users. 14 | - **Neo4j Integration**: Efficient graph data modeling using Neo4j. 15 | - **Dockerized**: Run with Docker and Docker Compose for easy setup and deployment. 16 | 17 | --- 18 | 19 | ## 🚀 Getting Started 20 | 21 | Follow the steps below to get the project up and running. 22 | 23 | ### Prerequisites 24 | 25 | Make sure you have the following installed: 26 | 27 | - **Go** (1.18 or higher) 28 | - **Docker** and **Docker Compose** 29 | 30 | ### Installation 31 | 32 | 1. **Clone the repository**: 33 | ```bash 34 | git clone https://github.com/mahdi-eth/neo4j-social-network.git 35 | cd neo4j-social-network 36 | ``` 37 | 38 | 2. **Set up Docker Compose**: Ensure Neo4j and the Go application run seamlessly using Docker Compose. 39 | 40 | ```bash 41 | docker-compose up --build 42 | ``` 43 | 44 | 3. **Access the Neo4j Browser**: Open your browser and go to http://localhost:7474. Use these credentials: 45 | 46 | - **Username**: neo4j 47 | - **Password**: test1234 48 | 49 | 50 | ## 🛠️ Usage 51 | 52 | ### See the network graph: 53 | 54 | ```go 55 | MATCH (u:User) RETURN u; 56 | ``` 57 | 58 | 59 | --------------------------------------------------------------------------------