SkillAgentSearch skills...

Neode

Neo4j OGM for Node.js

Install / Use

/learn @adam-cowley/Neode
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Neode

Neode is a Neo4j OGM for Node JS designed to take care of the CRUD boilerplate involved with setting up a neo4j project with Node. Just install, set up your models and go.

Getting Started

Installation

npm install --save neode

Usage

// index.js
import Neode from 'neode';

const instance = new Neode('bolt://localhost:7687', 'username', 'password');

Enterprise Mode

To initiate Neode in enterprise mode and enable enterprise features, provide a true variable as the fourth parameter.

// index.js
import Neode from 'neode';

const instance = new Neode('bolt://localhost:7687', 'username', 'password', true);

Usage with .env variables

npm i --save dotenv
// .env
NEO4J_PROTOCOL=neo4j
NEO4J_HOST=localhost
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=neo4j
NEO4J_PORT=7687
NEO4J_DATABASE=neo4j
NEO4J_ENCRYPTION=ENCRYPTION_OFF
// index.js
import Neode from 'neode';

const instance = Neode.fromEnv();

Additional Driver Config

Additional driver configuration can be passed as the fifth parameter in the constructor, or defined in .env:

NEO4J_ENCRYPTED=ENCRYPTION_ON                   # ENCRYPTION_ON or ENCRYPTION_OFF
NEO4J_TRUST=TRUST_SIGNED_CERTIFICATES           # TRUST_ALL_CERTIFICATES, TRUST_ON_FIRST_USE, TRUST_SIGNED_CERTIFICATES, TRUST_CUSTOM_CA_SIGNED_CERTIFICATES, TRUST_SYSTEM_CA_SIGNED_CERTIFICATES
NEO4J_TRUSTED_CERTIFICATES=/path/to/cert.pem
NEO4J_KNOWN_HOSTS=127.0.0.1
NEO4J_MAX_CONNECTION_POOLSIZE=100
NEO4J_MAX_TRANSACTION_RETRY_TIME=5000
NEO4J_LOAD_BALANCING_STRATEGY=least_connected   # least_connected or round_robin
NEO4J_MAX_CONNECTION_LIFETIME=36000
NEO4J_CONNECTION_TIMEOUT=36000
NEO4J_DISABLE_LOSSLESS_INTEGERS=false

Loading with Models

You can use the with() method to load multiple models at once.

const neode = require('neode')
    .fromEnv()
    .with({
        Movie: require('./models/Movie'),
        Person: require('./models/Person')
    });

Load from Directory

You can load a directory of models by calling the withDirectory() method.

// models/Person.js
module.exports = {
  id: {
    type: 'uuid',
    primary: true
  },
  name: 'string'
}
// index.js
instance.withDirectory(__dirname+'/models');

Defining a Node Definition

Neode revolves around the notion of node definitions, or Models. To interact with the graph, you will need to define a node, identified by a name and with a schema of properties.

instance.model(name, schema);

Schema Object

instance.model('Person', {
    person_id: {
        primary: true,
        type: 'uuid',
        required: true, // Creates an Exists Constraint in Enterprise mode
    },
    payroll: {
        type: 'number',
        unique: 'true', // Creates a Unique Constraint
    },
    name: {
        type: 'name',
        index: true, // Creates an Index
    },
    age: 'number' // Simple schema definition of property : type
});
Property Types

The following property types are supported:

  • string
  • number
  • int
  • integer
  • float
  • uuid
  • node
  • nodes
  • relationship
  • relationships
  • Temporal
    • date
    • time
    • datetime
    • localtime
    • localdatetime
    • duration
  • Spatial
    • point
    • distance
Validation

Validation is provided by the Joi library. Certain data types (float, integer, boolean) will also be type cast during the data cleansing process. For more information on the full range of validation options, read the Joi API documentation.

All Types

| option | type | description | example | | -- | -- | -- | -- | | allow | Array | Whitelist of values that are allowed | allow: ['A', 'B', 'C'] | | valid | Array | A strict whitelist of valid options. All others will be rejected. | valid: ['A', 'B', 'C'] | | invalid | Array | A list of forbidden values | invalid: ['A', 'B', 'C'] | | required | Boolean | Should this field be required? | required: true | | optional | Boolean | Allow the value to be undefined | optional: true | | forbidden | Boolean | Marks a key as forbidden which will not allow any value except undefined. Used to explicitly forbid keys. | forbidden: true | | strict | Boolean | prevent type casting for the current key | strict: true | strip | Boolean | Marks a key to be removed from a resulting object or array after validation. | strip: true | default | Mixed/Function | Default value for the property | default: () => new Date() | empty | Boolean | Considers anything that matches the schema to be empty | empty: true | error | Error/String/Function | Overrides the default error | error: errors => new CustomValidationError('Oh No!', errors)

Boolean

| option | type | description | example | | -- | -- | -- | -- | | truthy | String | falsy | String | insensitive | Boolean

Date, Time, DateTime, LocalDateTime, LocalTime

| option | type | description | example | | -- | -- | -- | -- | | before | String | Date, date string or "now" to compare to the current date | after | String | Date, date string or "now" to compare to the current date

Numbers (number, int, integer, float)

| option | type | description | example | | -- | -- | -- | -- | | min | Number | max | Number | integer | Boolean | Requires the number to be an integer | precision | Number | Specifies the maximum number of decimal places | precision: 2 | multiple | Number | Multiple of a number | multiple: 2 | positive | Boolean | negative | Boolean | port | Boolean | Requires the number to be a TCP port, so between 0 and 65535.

Strings

| option | type | description | example | | -- | -- | -- | -- | | insensitive | Boolean | min | Number | Min length | max | Number | Max length | truncate | Boolean | Will truncate value to the max length | creditCard | Boolean | Requires the number to be a credit card number (Using Luhn Algorithm). | length | Number | Exact string length | regex | Object | Regular expression rule | { pattern: /([A-Z]+)/, invert: true, name: 'myRule'} | replace | Object | Replace in value | { pattern: /(^[A-Z]+)/, replace: '-' } | alphanum | Boolean | Requires the string value to only contain a-z, A-Z, and 0-9. | token | Boolean | Requires the string value to only contain a-z, A-Z, 0-9, and underscore _. | email | Boolean/Object | | ip | Boolean/Object | | uri | Boolean/Object | | guid | Boolean | hex | Boolean/Object | base64 | Boolean/Object | hostname | Boolean | normalize | Boolean/String | lowercase | Boolean | uppercase | Boolean | trim | Boolean | isoDate | Boolean

Defining Relationships

Relationships can be created in the schema or defined retrospectively.

instance.model(label).relationship(type, relationship, direction, target, schema, eager, cascade, node_alias);
instance.model('Person').relationship('knows', 'relationship', 'KNOWS', 'out', 'Person', {
    since: {
        type: 'number',
        required: true,
    },
    defaulted: {
        type: 'string',
        default: 'default'
    }
});

Eager Loading

You can eager load relationships in a findAll() call by setting the eager property inside the relationship schema to true.

{
    acts_in: {
        type: "relationship",
        target: "Movie",
        relationship: "ACTS_IN",
        direction: "out",
        properties: {
            name: "string"
        },
        eager: true // <-- eager load this relationship
    }
}

Eager loaded relationships can be retrieved by using the get() method. A Collection instance will be returned.

const person = person.find({name: "Tom Hanks"})
const movies = person.get('acts_in');
const first = movies.first();

Extending a Schema definition

You can inherit the schema of a class and extend by calling the extend method.

instance.extend(original, new, schema)
instance.extend('Person', 'Actor', {
    acts_in: {
        type: "relationship",
        target: "Movie",
        relationship: "ACTS_IN",
        direction: "out",
        properties: {
            name: "string"
        }
    }
})

Reading

Running a Cypher Query

instance.cypher(query, params)
instance.cypher('MATCH (p:Person {name: $name}) RETURN p', {name: "Adam"})
    .then(res => {
        console.log(res.records.length);
    })

Running a Batch

Batch queries run within their own transaction. Transactions can be sent as either a string or an object containing query and param properties.

instance.batch(queries)
instance.batch([
    {query: 'CREATE (p:Person {name: $name}) RETURN p', params: {name: "Adam"}},
    {query: 'CREATE (p:Person {name: $name}) RETURN p', params: {name: "Joe"}},
    {query: 'MATCH (first:Person {name: $first_name}), (second:Person {name: $second_name}) CREATE (first)-[:KNOWS]->(second)', params: {name: "Joe"}}
])
    .then(res => {
        console.log(res.records.length);
    })

Get all Nodes

instance.all(label, properties)
instance.model(label).all(properties)
instance.all('Person', {name: 'Adam'}, {name: 'ASC', id: 'DESC'}, 1, 0)
    .then(collection => {
        console.log(collection.length); // 1
        console.log(collection.get(0).get('name')); // 'Adam'
    })

Get Node by Internal Node ID

instance.findById(label, id)
instance.model(label).findById(id)
instance.findById('Person', 1)
    .then(person => {
        console.log(person.id()); // 1
    });

Get Node by Primary Key

Neode will work out the

View on GitHub
GitHub Stars400
CategoryDevelopment
Updated29d ago
Forks70

Languages

JavaScript

Security Score

100/100

Audited on Feb 23, 2026

No findings