PHPackages                             ideepblue/neoeloquent - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. ideepblue/neoeloquent

ActiveLibrary[Database &amp; ORM](/categories/database)

ideepblue/neoeloquent
=====================

Laravel wrapper for the Neo4j graph database REST interface

v8.0.1(5y ago)08MITPHPPHP &gt;=7.3

Since Jun 5Pushed 4y agoCompare

[ Source](https://github.com/ideepblue/NeoEloquent)[ Packagist](https://packagist.org/packages/ideepblue/neoeloquent)[ RSS](/packages/ideepblue-neoeloquent/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (10)Versions (19)Used By (0)

[![Build Status](https://camo.githubusercontent.com/4569e0128bd4aeb1232ebb75979037e0060bc7b40bd8b1c400bff256d277c4dc/68747470733a2f2f7472617669732d63692e6f72672f556c6f6262792f4e656f456c6f7175656e742e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/Ulobby/NeoEloquent)[![Codacy Badge](https://camo.githubusercontent.com/548584ac87556375e74f1380dde0912342401c49447ff8e3e28ed897b8811e11/68747470733a2f2f6170692e636f646163792e636f6d2f70726f6a6563742f62616467652f47726164652f3462313864653965613435623462326339366138663738613235646236343830)](https://www.codacy.com/manual/berteltorp/NeoEloquent?utm_source=github.com&utm_medium=referral&utm_content=ulobby/NeoEloquent&utm_campaign=Badge_Grade)

NeoEloquent
===========

[](#neoeloquent)

Neo4j Graph Eloquent Driver for Laravel, this is a fork of [Vinelab/NeoEloquent](https://github.com/Vinelab/NeoEloquent) created by [Ulobby](https://www.ulobby.eu).

The versioning scheme for this repository follow Laravel, in so that the major version for this package corresponds to the major of laravel supported. Ex NeoEloquent v6 supports Laravel v6, and NeoEloquent v8 supports Laravel v8.

At Ulobby we use NeoEloquent in production for a lot of the crud operations in our Laravel based SaaS. We usually end up writing raw cypher for more complex operations, as a consequence of this we currently do not recommend using polymorphic-relationships.

Chat &amp; Support
------------------

[](#chat--support)

Join the [Official Neo4j Slack Group](https://neo4j.com/blog/public-neo4j-users-slack-group/) and use the #neo4j-php channel.

Quick Reference
---------------

[](#quick-reference)

- [Installation](#installation)
- [Configuration](#configuration)
- [Models](#models)
- [Relationships](#relationships)
- [Edges](#edges)
- [Migration](#migration)
- [Schema](#schema)
- [Aggregates](#aggregates)
- [Only in Neo](#only-in-neo)
- [Things To Avoid](#avoid)

Installation
------------

[](#installation)

Add the package to your `composer.json` and run `composer update`.

### Laravel 8

[](#laravel-8)

#### 8.0

[](#80)

```
{
    "require": {
        "ulobby/neoeloquent": "^8.0"
    }
}
```

### Laravel 7

[](#laravel-7)

#### 7.0

[](#70)

```
{
    "require": {
        "ulobby/neoeloquent": "^7.0"
    }
}
```

### Laravel 6

[](#laravel-6)

#### 6.0

[](#60)

```
{
    "require": {
        "ulobby/neoeloquent": "^6.0"
    }
}
```

Add the service provider in `app/config/app.php`:

```
'Vinelab\NeoEloquent\NeoEloquentServiceProvider',
```

The service provider will register all the required classes for this package and will also alias the `Model` class to `NeoEloquent` so you can simply `extend NeoEloquent` in your models.

Configuration
-------------

[](#configuration)

### Connection

[](#connection)

in `app/config/database.php` or in case of an environment-based configuration `app/config/[env]/database.php`make `neo4j` your default connection:

```
'default' => 'neo4j',
```

Add the connection defaults:

```
'connections' => [
    'neo4j' => [
        'driver' => 'neo4j',
        'host'   => env('DB_HOST', 'localhost'),
        'port'   => env('DB_PORT', '7474'),
        'username' => env('DB_USERNAME', null),
        'password' => env('DB_PASSWORD', null)
    ]
]
```

### Migration Setup

[](#migration-setup)

If you're willing to have migrations:

- create the folder `app/database/labels`
- modify `composer.json` and add `app/database/labels` to the `classmap` array
- run `composer dump-autoload`

### Documentation

[](#documentation)

Models
------

[](#models)

- [Node Labels](#namespaced-models)
- [Soft Deleting](#soft-deleting)

```
class User extends NeoEloquent {}
```

As simple as it is, NeoEloquent will generate the default node label from the class name, in this case it will be `:User`. Read about [node labels here](http://docs.neo4j.org/chunked/stable/rest-api-node-labels.html)

### Namespaced Models

[](#namespaced-models)

When you use namespaces with your models the label will consider the full namespace.

```
namespace Vinelab\Cms;

class Admin extends NeoEloquent { }
```

The generated label from that relationship will be `VinelabCmsAdmin`, this is necessary to make sure that labels do not clash in cases where we introduce another `Admin` instance like `Vinelab\Blog\Admin` then things gets messy with `:Admin` in the database.

### Custom Node Labels

[](#custom-node-labels)

You may specify the label(s) you wish to be used instead of the default generated, they are also case sensitive so they will be stored as put here.

```
class User extends NeoEloquent {

    protected $label = 'User'; // or array('User', 'Fan')

    protected $fillable = ['name', 'email'];
}

$user = User::create(['name' => 'Some Name', 'email' => 'some@email.com']);
```

NeoEloquent has a fallback support for the `$table` variable that will be used if found and there was no `$label` defined on the model.

```
class User extends NeoEloquent {

    protected $table = 'User';

}
```

Do not worry about the labels formatting, You may specify them as `array('Label1', 'Label2')` or separate them by a column `:` and prepending them with a `:` is optional.

### Soft Deleting

[](#soft-deleting)

#### Laravel 5

[](#laravel-5)

To enable soft deleting you'll need to `use Vinelab\NeoEloquent\Eloquent\SoftDeletes`instead of `Illuminate\Database\Eloquent\SoftDeletes` and just like Eloquent you'll need the `$dates` in your models as follows:

```
use Vinelab\NeoEloquent\Eloquent\SoftDeletes;

class User extends NeoEloquent {

    use SoftDeletes;

    protected $dates = ['deleted_at'];

}
```

Relationships
-------------

[](#relationships)

- [One-To-One](#one-to-one)
- [One-To-Many](#one-to-many)
- [Many-To-Many](#many-to-many)
- [Polymorphic](#polymorphic)

Let's go through some examples of relationships between Nodes.

### One-To-One

[](#one-to-one)

```
class User extends NeoEloquent {

    public function phone()
    {
        return $this->hasOne('Phone');
    }
```

This represents an `OUTGOING` relationship direction from the `:User` node to a `:Phone`.

##### Saving

[](#saving)

```
$phone = new Phone(['code' => 961, 'number' => '98765432'])
$relation = $user->phone()->save($phone);
```

The Cypher performed by this statement will be as follows:

```
MATCH (user:`User`)
WHERE id(user) = 1
CREATE (user)-[:PHONE]->(phone:`Phone` {code: 961, number: '98765432', created_at: 7543788, updated_at: 7543788})
RETURN phone;

```

##### Defining The Inverse Of This Relation

[](#defining-the-inverse-of-this-relation)

```
class Phone extends NeoEloquent {

    public function user()
    {
        return $this->belongsTo('User');
    }
}
```

This represents an `INCOMING` relationship direction from the `:User` node to this `:Phone` node.

##### Associating Models

[](#associating-models)

Due to the fact that we do not deal with **foreign keys**, in our case it is much more than just setting the foreign key attribute on the parent model. In Neo4j (and Graph in general) a relationship is an entity itself that can also have attributes of its own, hence the introduction of [**Edges**](#Edges)

> *Note:* Associated models does not persist relations automatically when calling `associate()`.

```
$account = Account::find(1986);

// $relation will be Vinelab\NeoEloquent\Eloquent\Edges\EdgeIn
$relation = $user->account()->associate($account);

// Save the relation
$relation->save();
```

The Cypher performed by this statement will be as follows:

```
MATCH (account:`Account`), (user:`User`)
WHERE id(account) = 1986 AND id(user) = 9862
MERGE (account)hasMany('Post', 'POSTED');
    }
}
```

This represents an `OUTGOING` relationship direction from the `:User` node to the `:Post` node.

```
$user = User::find(1);
$post = new Post(['title' => 'The Title', 'body' => 'Hot Body']);
$user->posts()->save($post);
```

Similar to `One-To-One` relationships the returned value from a `save()` statement is an `Edge[In|Out]`

The Cypher performed by this statement will be as follows:

```
MATCH (user:`User`)
WHERE id(user) = 1
CREATE (user)-[rel_user_post:POSTED]->(post:`Post` {title: 'The Title', body: 'Hot Body', created_at: '15-05-2014', updated_at: '15-05-2014'})
RETURN rel_user_post;

```

##### Defining The Inverse Of This Relation

[](#defining-the-inverse-of-this-relation-1)

```
class Post extends NeoEloquent {

    public function author()
    {
        return $this->belongsTo('User', 'POSTED');
    }
}
```

This represents an `INCOMING` relationship direction from the `:User` node to this `:Post` node.

### Many-To-Many

[](#many-to-many)

```
class User extends NeoEloquent {

    public function followers()
    {
        return $this->belongsToMany('User', 'FOLLOWS');
    }
}
```

This represents an `INCOMING` relationship between a `:User` node and another `:User`.

```
$jd = User::find(1012);
$mc = User::find(1013);
```

`$jd` follows `$mc`:

```
$jd->followers()->save($mc);
```

Or using the `attach()` method:

```
$jd->followers()->attach($mc);
// Or..
$jd->followers()->attach(1013); // 1013 being the id of $mc ($mc->getKey())
```

The Cypher performed by this statement will be as follows:

```
MATCH (user:`User`), (followers:`User`)
WHERE id(user) = 1012 AND id(followers) = 1013
CREATE (followers)-[:FOLLOWS]->(user)
RETURN rel_follows;

```

`$mc` follows `$jd` back:

```
$mc->followers()->save($jd);
```

The Cypher performed by this statement will be as follows:

```
MATCH (user:`User`), (followers:`User`)
WHERE id(user) = 1013 AND id(followers) = 1012
CREATE (user)-[rel_user_followers:FOLLOWS]->(followers)
RETURN rel_follows;

```

get the followers of `$jd`

```
$followers = $jd->followers;
```

The Cypher performed by this statement will be as follows:

```
MATCH (user:`User`), (followers:`User`), (user)-[rel_user_followers:FOLLOWS]-(followers)
WHERE id(user) = 1012
RETURN rel_follows;

```

### Dynamic Properties

[](#dynamic-properties)

```
class Phone extends NeoEloquent {

    public function user()
    {
        return $this->belongsTo('User');
    }

}

$phone = Phone::find(1006);
$user = $phone->user;
// or getting an attribute out of the related model
$name = $phone->user->name;
```

### Polymorphic

[](#polymorphic)

The concept behind Polymorphic relations is purely relational to the bone but when it comes to graph we are representing it as a [HyperEdge](http://docs.neo4j.org/chunked/stable/cypher-cookbook-hyperedges.html).

Hyper edges involves three models, the **parent** model, **hyper** model and **related** model represented in the following figure:

[![HyperEdges](https://camo.githubusercontent.com/f1291f47c505b67b5ac2da31f47eaa71e40e3b637600c35e80608cef76632697/68747470733a2f2f676f6f676c6564726976652e636f6d2f686f73742f30427a6e7a5a326c42625430634c573959636a4e6c646c4a6b6358632f4879706572456467652e706e67 "HyperEdges")](https://camo.githubusercontent.com/f1291f47c505b67b5ac2da31f47eaa71e40e3b637600c35e80608cef76632697/68747470733a2f2f676f6f676c6564726976652e636f6d2f686f73742f30427a6e7a5a326c42625430634c573959636a4e6c646c4a6b6358632f4879706572456467652e706e67)

Similarly in code this will be represented by three models `User` `Comment` and `Post`where a `User` with id 1 posts a `Post` and a `User` with id 6 `COMMENTED` a `Comment` `ON` that `Post`as follows:

```
class User extends NeoEloquent {

    public function comments($morph = null)
    {
        return $this->hyperMorph($morph, 'Comment', 'COMMENTED', 'ON');
    }

}
```

In order to keep things simple but still involving the three models we will have to pass the `$morph` which is any `commentable` model, in our case it's either a `Video` or a `Post` model.

> **Note:** Make sure to have it defaulting to `null` so that we can Dynamicly or Eager load with `$user->comments` later on.

Creating a `Comment` with the `create()` method.

```
$user = User::find(6);
$post = Post::find(2);

$user->comments($post)->create(['text' => 'Totally agree!', 'likes' => 0, 'abuse' => 0]);
```

As usual we will have returned an Edge, but this time it's not directed it is an instance of `HyperEdge`, read more about [HyperEdges here](#hyperedge).

Or you may save a Comment instance:

```
$comment = new Comment(['text' => 'Magnificent', 'likes' => 0, 'abuse' => 0]);

$user->comments($post)->save($comment);
```

Also all the functionalities found in a `BelongsToMany` relationship are supported like attaching models by Ids:

```
$user->comments($post)->attach([$id, $otherId]);
```

Or detaching models:

```
$user->comments($post)->detach($comment); // or $comment->id
```

Sync too:

```
$user->comments($post)->sync([$id, $otherId, $someId]);
```

#### Retrieving Polymorphic Relations

[](#retrieving-polymorphic-relations)

From our previous example we will use the `Video` model to retrieve their comments:

```
class Video extends NeoEloquent {

    public function comments()
    {
        return $this->morphMany('Comment', 'ON');
    }

}
```

##### Dynamicly Loading Morph Model

[](#dynamicly-loading-morph-model)

```
$video = Video::find(3);
$comments = $video->comments;
```

##### Eager Loading Morph Model

[](#eager-loading-morph-model)

```
$video = Video::with('comments')->find(3);
foreach ($video->comments as $comment)
{
    //
}
```

#### Retrieving The Inverse of a Polymorphic Relation

[](#retrieving-the-inverse-of-a-polymorphic-relation)

```
class Comment extends NeoEloquent {

    public function commentable()
    {
        return $this->morphTo();
    }

}
```

```
$postComment = Comment::find(7);
$post = $comment->commentable;

$videoComment = Comment::find(5);
$video = $comment->commentable;

// You can also eager load them
Comment::with('commentable')->get();
```

You may also specify the type of morph you would like returned:

```
class Comment extends NeoEloquent {

    public function post()
    {
        return $this->morphTo('Post', 'ON');
    }

    public function video()
    {
        return $this->morphTo('Video', 'ON');
    }

}
```

#### Polymorphic Relations In Short

[](#polymorphic-relations-in-short)

To drill things down here's how our three models involved in a Polymorphic relationship connect:

```
class User extends NeoEloquent {

    public function comments($morph = null)
    {
        return $this->hyperMorph($morph, 'Comment', 'COMMENTED', 'ON');
    }

}
```

```
class Post extends NeoEloquent { // Video is the same as this one

    public function comments()
    {
        return $this->morphMany('Comment', 'ON');
    }

}
```

```
class Comment extends NeoEloquent {

    public function commentable()
    {
        return $this->morphTo();
    }

}
```

### Eager Loading

[](#eager-loading)

```
class Book extends NeoEloquent {

    public function author()
    {
        return $this->belongsTo('Author');
    }
}
```

Loading authors with their books with the least performance overhead possible.

```
foreach (Book::with('author')->get() as $book)
{
    echo $book->author->name;
}
```

Only two Cypher queries will be run in the loop above:

```
MATCH (book:`Book`) RETURN *;

MATCH (book:`Book`), (book)belongsTo('User', 'LOCATED_AT');
    }

}
```

To associate a `User` to a `Location`:

```
$location = Location::find(1922);
$user = User::find(3876);
$relation = $location->associate($user);
```

which in Cypher land will map to `(:Location)associate($user);
$location = $relation->parent();
$user = $relation->related();
```

#### EdgeOut

[](#edgeout)

Represents an `OUTGOING` direction relationship from the parent model to the related model.

```
class User extends NeoEloquent {

    public function posts()
    {
        return $this->hasMany('Post', 'POSTED');
    }

}
```

To save an outgoing edge from `:User` to `:Post` it goes like:

```
$post = new Post(['...']);
$posted = $user->posts()->save($post);
```

Which in Cypher would be `(:User)-[:POSTED]->(:Post)` and `$posted` being the `EdgeOut` instance.

And fetch the related models:

```
$edge = $user->posts()->save($post);
$user = $edge->parent();
$post = $edge->related();
```

#### HyperEdge

[](#hyperedge)

This edge comes as a result of a [Polymorphic Relation](#polymorphic) representing an edge involving two other edges **left** and **right** that can be accessed through the `left()` and `right()` methods.

This edge is treated a bit different than the others since it is not a direct relationship between two models which means it has no specific direction.

```
$edge = $user->comments($post)->attach($comment);
// Access the left and right edges
$left = $edge->left();
$user = $left->parent();
$comment = $left->related();

$right = $edge->right();
$comment = $right->parent();
$post = $right->related();
```

### Working With Edges

[](#working-with-edges)

As stated earlier **Edges** are entities to Graph unlike *SQL* where they are a matter of a foreign key having the value of the parent model as an attribute on the belonging model or in *Documents* where they are either embeds or ids as references. So we developed them to be *light models* which means you can work with them as if you were working with an `Eloquent` instance - to a certain extent, except [HyperEdges](#hyperedges).

```
// Create a new relationship
$relation = $location->associate($user); // Vinelab\NeoEloquent\Eloquent\Edges\EdgeIn

// Save the relationship to the database
$relation->save(); // true
```

In the case of a `HyperEdge` you can access all three models as follows:

```
$edge    = $user->comments($post)->save($comment);
$user    = $edge->parent();
$comment = $edge->hyper();
$post    = $edge->related();
```

#### Edge Attributes

[](#edge-attributes)

By default, edges will have the timestamps `created_at` and `updated_at` automatically set and updated **only if** timestamps are enabled by setting `$timestamps` to `true`on the parent model.

```
$located_at = $location->associate($user);
$located_at->since = 1966;
$located_at->present = true;
$located_at->save();

// $created_at and $updated_at are Carbon\Carbon instances
$created_at = $located_at->created_at;
$updated_at = $located_at->updated_at;
```

##### Retrieve an Edge from a Relation

[](#retrieve-an-edge-from-a-relation)

The same way an association will create an `EdgeIn` relationship we can retrieve the edge between two models by calling the `edge($model)` method on the `belongsTo`relationship.

```
$location = Location::find(1892);
$edge = $location->user()->edge();
```

You may also specify the model at the other side of the edge.

> Note: By default NeoEloquent will try to perform the `$location->user` internally to figure out the related side of the edge based on the relation function name, in this case it's `user()`.

```
$location = Location::find(1892);
$edge = $location->user()->edge($location->user);
```

Only in Neo
-----------

[](#only-in-neo)

- [CreateWith](#createwith)

Here you will find NeoEloquent-specific methods and implementations that with the wonderful Eloquent methods would make working with Graph and Neo4j a blast!

### CreateWith

[](#createwith)

- [Creating Relations](#creating-new-records-and-relations)
- [Attaching Relations](#attaching-existing-records-as-relations)

This method will "kind of" fill the gap between relational and document databases, it allows the creation of multiple related models with one database hit.

#### Creating New Records and Relations

[](#creating-new-records-and-relations)

Here's an example of creating a post with attached photos and videos:

```
class Post extends NeoEloquent {

    public function photos()
    {
        return $this->hasMany('Photo', 'PHOTO');
    }

    public function videos()
    {
        return $this->hasMany('Video', 'VIDEO');
    }
}
```

```
Post::createWith(['title' => 'the title', 'body' => 'the body'], [
    'photos' => [
        [
            'url'      => 'http://url',
            'caption'  => '...',
            'metadata' => '...'
        ],
        [
            'url' => 'http://other.url',
            'caption' => 'the bay',
            'metadata' => '...'
        ]
    ],

    'videos' => [
        'title' => 'Boats passing us by',
        'description' => '...'
    ]
]);
```

> The keys `photos` and `videos` must be the same as the relation method names in the `Post` model.

The Cypher query performed by the example above is:

```
CREATE (post:`Post` {title: 'the title', body: 'the body'}),
(post)-[:PHOTO]->(:`Photo` {url: 'http://url', caption: '...', metadata: '...'}),
(post)-[:PHOTO]->(:`Photo` {url: 'http://other', caption: 'the bay', metadata: '...'}),
(post)-[:VIDEO]->(:`Video` {title: 'Boats passing us by', description: '...'});

```

We will get the nodes created with their relations as such:

[![CreateWith](https://camo.githubusercontent.com/6ac37c66cfd7da27d70f481afae4b753d046658909d7f4511a1fccbafcaa0ead/68747470733a2f2f676f6f676c6564726976652e636f6d2f686f73742f30427a6e7a5a326c42625430634c573959636a4e6c646c4a6b6358632f637265617465576974682d707265766965772e64622e706e67 "CreateWith")](https://camo.githubusercontent.com/6ac37c66cfd7da27d70f481afae4b753d046658909d7f4511a1fccbafcaa0ead/68747470733a2f2f676f6f676c6564726976652e636f6d2f686f73742f30427a6e7a5a326c42625430634c573959636a4e6c646c4a6b6358632f637265617465576974682d707265766965772e64622e706e67)

You may also mix models and attributes as relation values but it is not necessary since NeoEloquent will pass the provided attributes through the `$fillable`filter pipeline:

```
$videos = new Video(['title' => 'foo', 'description' => 'bar']);
Post::createWith($info, compact('videos'));
```

You may also use a single array of attributes as such:

```
class User extends NeoEloquent {

    public function account()
    {
        return $this->hasOne('Account');
    }
}

User::createWith(['name' => 'foo'], ['account' => ['guid' => 'bar', 'email' => 'some@mail.net']]);
```

#### Attaching Existing Records as Relations

[](#attaching-existing-records-as-relations)

`createWith` is intelligent enough to know the difference when you pass an existing model, a model Id or new records that you need to create which allows mixing new records with existing ones.

```
class Post extends NeoEloquent {

    public function tags()
    {
        return $this->hasMany('Tag', 'TAG');
    }
}
```

```
$tag1 = Tag::create(['title' => 'php']);
$tag2 = Tag::create(['title' => 'dev']);

$post = Post::createWith(['title' => 'foo', 'body' => 'bar'], ['tags' => [$tag1, $tag2]]);
```

And we will get the `Post` related to the existing `Tag` nodes.

Or using the `id` of the model:

```
Post::createWith(['title' => 'foo', 'body' => 'bar'], ['tags' => 1, 'privacy' => 2]);
```

The Cypher for the query that attaches records would be:

```
CREATE (post:`Post` {title: 'foo', 'body' => 'bar'})
WITH post
MATCH (tag:`Tag`)
WHERE id(tag) IN [1, 2]
CREATE (post)-[:TAG]->(tag);

```

Migration
---------

[](#migration)

For migrations to work please perform the following:

- create the folder `app/database/labels`
- modify `composer.json` and add `app/database/labels` to the `classmap` array

Since Neo4j is a schema-less database you don't need to predefine types of properties for labels. However you will be able to perform [Indexing](http://neo4j.com/docs/stable/query-schema-index.html) and [Constraints](http://neo4j.com/docs/stable/query-constraints.html) using NeoEloquent's pain-less [Schema](#schema).

#### Commands

[](#commands)

NeoEloquent introduces new commands under the `neo4j` namespace so you can still use Eloquent's migration commands side-by-side.

Migration commands are the same as those of Eloquent, in the form of `neo4j:migrate[:command]`

```
neo4j:make:migration                 Create a new migration file
neo4j:migrate                        Run the database migrations
neo4j:migrate:reset                  Rollback all database migrations
neo4j:migrate:refresh                Reset and re-run all migrations
neo4j:migrate:rollback               Rollback the last database migration

```

### Creating Migrations

[](#creating-migrations)

Like in Laravel you can create a new migration by using the `make` command with Artisan:

```
php artisan neo4j:migrate:make create_user_label

```

Label migrations will be placed in `app/database/labels`

You can add additional options to commands like:

```
php artisan neo4j:migrate:make foo --path=app/labels
php artisan neo4j:migrate:make create_user_label --create=User
php artisan neo4j:migrate:make create_user_label --label=User

```

### Running Migrations

[](#running-migrations)

##### Run All Outstanding Migrations

[](#run-all-outstanding-migrations)

```
php artisan neo4j:migrate

```

##### Run All Outstanding Migrations For A Path

[](#run-all-outstanding-migrations-for-a-path)

```
php artisan neo4j:migrate --path=app/foo/labels

```

##### Run All Outstanding Migrations For A Package

[](#run-all-outstanding-migrations-for-a-package)

```
php artisan neo4j:migrate --package=vendor/package

```

> Note: If you receive a "class not found" error when running migrations, try running the `composer dump-autoload` command.

#### Forcing Migrations In Production

[](#forcing-migrations-in-production)

To force-run migrations on a production database you can use:

```
php artisan neo4j:migrate --force

```

### Rolling Back Migrations

[](#rolling-back-migrations)

##### Rollback The Last Migration Operation

[](#rollback-the-last-migration-operation)

```
php artisan neo4j:migrate:rollback

```

##### Rollback all migrations

[](#rollback-all-migrations)

```
php artisan neo4j:migrate:reset

```

##### Rollback all migrations and run them all again

[](#rollback-all-migrations-and-run-them-all-again)

```
php artisan neo4j:migrate:refresh

php artisan neo4j:migrate:refresh --seed

```

Schema
------

[](#schema)

NeoEloquent will alias the `Neo4jSchema` facade automatically for you to be used in manipulating labels.

```
Neo4jSchema::label('User', function(Blueprint $label)
{
    $label->unique('uuid');
});
```

If you decide to write Migration classes manually (not using the generator) make sure to have these `use` statements in place:

- `use Vinelab\NeoEloquent\Schema\Blueprint;`
- `use Vinelab\NeoEloquent\Migrations\Migration;`

Currently Neo4j supports `UNIQUE` constraint and `INDEX` on properties. You can read more about them at

#### Schema Methods

[](#schema-methods)

CommandDescription`$label->unique('email')`Adding a unique constraint on a property`$label->dropUnique('email')`Dropping a unique constraint from property`$label->index('uuid')`Adding index on property`$label->dropIndex('uuid')`Dropping index from property### Droping Labels

[](#droping-labels)

```
Neo4jSchema::drop('User');
Neo4jSchema::dropIfExists('User');
```

### Renaming Labels

[](#renaming-labels)

```
Neo4jSchema::renameLabel($from, $to);
```

### Checking Label's Existence

[](#checking-labels-existence)

```
if (Neo4jSchema::hasLabel('User')) {

} else {

}
```

### Checking Relation's Existence

[](#checking-relations-existence)

```
if (Neo4jSchema::hasRelation('FRIEND_OF')) {

} else {

}
```

You can read more about migrations and schema on:

Aggregates
----------

[](#aggregates)

In addition to the Eloquent builder aggregates, NeoEloquent also has support for Neo4j specific aggregates like *percentile* and *standard deviation*, keeping the same function names for convenience. Check [the docs](http://docs.neo4j.org/chunked/stable/query-aggregation.html) for more.

> `table()` represents the label of the model

```
$users = DB::table('User')->count();

$distinct = DB::table('User')->countDistinct('points');

$price = DB::table('Order')->max('price');

$price = DB::table('Order')->min('price');

$price = DB::table('Order')->avg('price');

$total = DB::table('User')->sum('votes');

$disc = DB::table('User')->percentileDisc('votes', 0.2);

$cont = DB::table('User')->percentileCont('votes', 0.8);

$deviation = DB::table('User')->stdev('sex');

$population = DB::table('User')->stdevp('sex');

$emails = DB::table('User')->collect('email');

```

Changelog
---------

[](#changelog)

Check the [Releases](https://github.com/Vinelab/NeoEloquent/releases) for details.

Avoid
-----

[](#avoid)

Here are some constraints and Graph-specific gotchas, a list of features that are either not supported or not recommended.

### JOINS 😖

[](#joins-confounded)

- They make no sense for Graph, plus Graph hates them! Which makes them unsupported on purpose. If migrating from an `SQL`-based app they will be your boogie monster.

### Pivot Tables in Many-To-Many Relationships

[](#pivot-tables-in-many-to-many-relationships)

This is not supported, instead we will be using [Edges](#edges) to work with relationships between models.

### Nested Arrays and Objects

[](#nested-arrays-and-objects)

- Due to the limitations imposed by the objects map types that can be stored in a single, you can never have nested *arrays* or *objects* in a single model, make sure it's flat. *Example:*

```
// Don't
User::create(['name' => 'Some Name', 'location' => ['lat' => 123, 'lng'=> -123 ] ]);
```

Check out the [createWith()](#createwith) method on how you can achieve this in a Graph way.

Tests
-----

[](#tests)

- install a Neo4j instance and run it with the default configuration `localhost:7474`
- make sure the database graph is empty to avoid conflicts
- after running `composer install` there should be `/vendor/bin/phpunit`
- run `./vendor/bin/phpunit` after making sure that the Neo4j instance is running

> Tests marked as incomplete means they are either known issues or non-supported features, check included messages for more info.

###  Health Score

29

—

LowBetter than 60% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity4

Limited adoption so far

Community19

Small or concentrated contributor base

Maturity66

Established project with proven stability

 Bus Factor1

Top contributor holds 61.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~76 days

Recently: every ~14 days

Total

15

Last Release

1824d ago

Major Versions

v6.1.0 → v7.0.02021-01-17

v7.0.0 → v8.0.02021-01-19

v6.2.0 → v8.0.12021-02-16

v6.2.1 → v7.0.12021-03-18

v6.3.0 → 7.0.x-dev2021-05-12

PHP version history (3 changes)v1.4.7PHP &gt;=7.1.3

v1.4.8PHP &gt;=7.2

v8.0.0PHP &gt;=7.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/a984ab80ee4e28e178df976c0ceb9dcbe16c5265db78c54e6c57a457ea5056da?d=identicon)[ideepblue](/maintainers/ideepblue)

---

Top Contributors

[![Mulkave](https://avatars.githubusercontent.com/u/2647333?v=4)](https://github.com/Mulkave "Mulkave (297 commits)")[![berteltorp](https://avatars.githubusercontent.com/u/2384153?v=4)](https://github.com/berteltorp "berteltorp (74 commits)")[![SimonThordal](https://avatars.githubusercontent.com/u/1394424?v=4)](https://github.com/SimonThordal "SimonThordal (52 commits)")[![cheerfulstoic](https://avatars.githubusercontent.com/u/301415?v=4)](https://github.com/cheerfulstoic "cheerfulstoic (9 commits)")[![harris21](https://avatars.githubusercontent.com/u/1542015?v=4)](https://github.com/harris21 "harris21 (9 commits)")[![KinaneD](https://avatars.githubusercontent.com/u/12595235?v=4)](https://github.com/KinaneD "KinaneD (6 commits)")[![heydavid713](https://avatars.githubusercontent.com/u/11636521?v=4)](https://github.com/heydavid713 "heydavid713 (5 commits)")[![lamoni](https://avatars.githubusercontent.com/u/5675626?v=4)](https://github.com/lamoni "lamoni (5 commits)")[![rennokki](https://avatars.githubusercontent.com/u/21983456?v=4)](https://github.com/rennokki "rennokki (5 commits)")[![tomb10516](https://avatars.githubusercontent.com/u/12363349?v=4)](https://github.com/tomb10516 "tomb10516 (3 commits)")[![ctorresr](https://avatars.githubusercontent.com/u/12038330?v=4)](https://github.com/ctorresr "ctorresr (2 commits)")[![holix](https://avatars.githubusercontent.com/u/235733?v=4)](https://github.com/holix "holix (2 commits)")[![joseraul](https://avatars.githubusercontent.com/u/676681?v=4)](https://github.com/joseraul "joseraul (2 commits)")[![thylo](https://avatars.githubusercontent.com/u/1242863?v=4)](https://github.com/thylo "thylo (1 commits)")[![alex-jf](https://avatars.githubusercontent.com/u/1942761?v=4)](https://github.com/alex-jf "alex-jf (1 commits)")[![whoacowboy](https://avatars.githubusercontent.com/u/8116953?v=4)](https://github.com/whoacowboy "whoacowboy (1 commits)")[![apopiak](https://avatars.githubusercontent.com/u/6952290?v=4)](https://github.com/apopiak "apopiak (1 commits)")[![charles7aponte](https://avatars.githubusercontent.com/u/2250854?v=4)](https://github.com/charles7aponte "charles7aponte (1 commits)")[![dafyd](https://avatars.githubusercontent.com/u/301993?v=4)](https://github.com/dafyd "dafyd (1 commits)")[![dgerike](https://avatars.githubusercontent.com/u/408921?v=4)](https://github.com/dgerike "dgerike (1 commits)")

---

Tags

laraveldatabaseneo4jgraphneoeloquent

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/ideepblue-neoeloquent/health.svg)

```
[![Health](https://phpackages.com/badges/ideepblue-neoeloquent/health.svg)](https://phpackages.com/packages/ideepblue-neoeloquent)
```

###  Alternatives

[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k7.2M71](/packages/mongodb-laravel-mongodb)[vinelab/neoeloquent

Laravel wrapper for the Neo4j graph database REST interface

65393.1k1](/packages/vinelab-neoeloquent)[tucker-eric/eloquentfilter

An Eloquent way to filter Eloquent Models

1.8k4.8M26](/packages/tucker-eric-eloquentfilter)[ulobby/neoeloquent

Laravel wrapper for the Neo4j graph database REST interface

4473.4k](/packages/ulobby-neoeloquent)[toponepercent/baum

Baum is an implementation of the Nested Set pattern for Eloquent models.

3154.7k](/packages/toponepercent-baum)[aimeos/laravel-nestedset

Nested Set Model for Laravel

292.0k2](/packages/aimeos-laravel-nestedset)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
