Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

1095 lines (840 sloc) 39.302 kb

Seraph.js

A terse & familiar binding to the Neo4j REST API that is idiomatic to node.js.

Install

npm install seraph

Quick Example

var db = require("seraph")("http://localhost:7474");

db.save({ name: "Test-Man", age: 40 }, function(err, node) {
  if (err) throw err;
  console.log("Test-Man inserted.");

  db.delete(node, function(err) {
    if (err) throw err;
    console.log("Test-Man away!");
  });
});

Documentation

Initialization

  • seraph - initialize the seraph client

Generic Operations

  • query - perform a cypher query and parse the results
  • rawQuery - perform a cypher query and return unparsed results

API Communication Operations

  • operation - create a representation of a REST API call
  • call - take an operation and call it
  • batch - perform a series of atomic operations with one api call.

Node Operations

Relationship Operations

Index Operations

Compatibility

Seraph has been tested with Neo4j 2.0.0-M03. If you would like to test compatibility with another version of neo4j, change the version values stored in test/util/database.js.

Testing

You can test Seraph simply by running npm test. It will spin up its own neo4j instance for testing. Note that the first time you run your tests (or change neo4j version), a new version of neo4j will need to be downloaded. That can, of course, take a little time.

Initialization

seraph([server|options])

Creates and returns the Seraph instance. If no parameters are given, assumes the Neo4J REST API is running locally at the default location http://localhost:7474/db/data.

Arguments

  • options (default={ server: "http://localhost:7474", endpoint: "/db/data" } - server is protocol and authority part of Neo4J REST API URI, and endpoint should be the path segment of the URI.
  • server (string) - Short form to specify server parameter only. "http://localhorse:4747" is equivalent to { server: "http://localhorse:4747" }.

Example

// To http://localhost:7474/db/data
var dbLocal = require("seraph")();

// To http://example.com:53280/neo
var dbRemote = require("seraph")({ server: "http://example.com:53280",
                                   endpoint: "/neo" });

// Copy node#13 from remote server
dbRemote.read({ id: 13 }, function(err, node) {
  if (err) throw err;
  delete node.id; // copy instead of overwriting local node#13
  dbLocal.save(node, function(err, nodeL) {
    if (err) throw err;
    console.log("Copied remote node#13 to " +
                "local node#" + nodeL.id.toString() + ".");
  });
});

Generic Operations

query(query, [params,] callback), rawQuery(query, [params,] callback)

rawQuery performs a cypher query and returns the results directly from the REST API.
query performs a cypher query and map the columns and results together.

Note: if you're performing large queries it may be advantageous to use queryRaw, since query attempts to infer whole nodes and relationships that are returned (in order to transform them into a nicer format).

Arguments

  • query - Cypher query as a format string.
  • params (optional, default={}). Replace {key} parts in query string. See cypher documentation for details. note that if you want to send a list of ids as a parameter, you should send them as an array, rather than a string representing them ([2,3] rather than "2,3").
  • callback - (err, result). Result is an array of objects.

Example

Given database:

{ name: 'Jon', age: 23, id: 1 }
{ name: 'Neil', age: 60, id: 2 }
{ name: 'Katie', age: 29, id: 3 }
// 1 --knows--> 2
// 1 --knows--> 3

Return all people Jon knows:

var cypher = "START x = node({id}) "
           + "MATCH x -[r]-> n "
           + "RETURN n "
           + "ORDER BY n.name";

db.query(cypher, {id: 1}, function(err, result) {
  if (err) throw err;
  assert.deepEqual(result, [
    { name: 'Katie', age: 29, id: 3 },
    { name: 'Neil', age: 60, id: 2 }
  ]);
};

db.rawQuery(cypher, {id: 3}, function(err, result) {
  if (err) throw err;
  // result contains the raw response from neo4j's rest API. See
  // http://docs.neo4j.org/chunked/milestone/rest-api-cypher.html
  // for more info
})

operation(path, [method='get/post'], [data])

Create an operation object that will be passed to call.

Arguments

  • path - the path fragment of the request URL with no leading slash.
  • method (optional, default='GET'|'POST') - the HTTP method to use. When data is an object, method defaults to 'POST'. Otherwise, method defaults to GET.
  • data (optional) - an object to send to the server with the request.

Example

var operation = db.operation('node/4285/properties', 'PUT', { name: 'Jon' });
db.call(operation, function(err) {
  if (!err) console.log('Set `name` to `Jon` on node 4285!')
});

call(operation, callback)

Perform an HTTP request to the server.

If the body is some JSON, it is parsed and passed to the callback.If the status code is not in the 200's, an error is passed to the callback.

Arguments

  • operation - an operation created by operation that specifies what to request from the server
  • callback - function(err, result, response). result is the JSON parsed body from the server (otherwise empty). response is the response object from the request.

Example

var operation = db.operation('node/4285/properties');
db.call(operation, function(err, properties) {
  if (err) throw err;

  // `properties` is an object containing the properties from node 4285
});

Batching/transactions - batch([operations, callback])

Batching provides a method of performing a series of operations atomically. You could also call it a transaction. It has the added benefit of being performed all in a single call to the neo4j api, which theoretically should result in improved performance when performing more than one operation at the same time.

When you create a batch, you're given a new seraph object to use. All calls to this object will be added to the batch. Note that once a batch is committed, you should no longer use this object.

How do I use it?

There's two ways. You can do the whole thing asynchronously, and commit the transaction whenever you want, or you can do it synchronously, and have the transaction committed for you as soon as your function is finished running. Here's a couple of examples of performing the same operations with batch synchronously and asynchronously:

Asynchronously
var txn = db.batch();

txn.save({ title: 'Kaikki Askeleet' });
txn.save({ title: 'Sinä Nukut Siinä' });
txn.save({ title: 'Pohjanmaa' });

txn.commit(function(err, results) {
  /* results -> [{ id: 1, title: 'Kaikki Askeleet' },
                 { id: 2, title: 'Sinä Nukut Siinä' },
                 { id: 3, title: 'Pohjanmaa' }] */
});
Synchronously

Note - it's only the creation of operations that is synchronous. The actual API call is asynchronous still, of course.

db.batch(function(txn) {
  txn.save({ title: 'Kaikki Askeleet' });
  txn.save({ title: 'Sinä Nukut Siinä' });
  txn.save({ title: 'Pohjanmaa' });
}, function(err, results) {
  /* results -> [{ id: 1, title: 'Kaikki Askeleet' },
                 { id: 2, title: 'Sinä Nukut Siinä' },
                 { id: 3, title: 'Pohjanmaa' }] */
});

What happens to my callbacks?

You can still pass callbacks to operations on a batch transaction. They will perform as you expect, but they will not be called until after the batch has been committed. Here's an example of using callbacks as normal:

var txn = db.batch();

txn.save({ title: 'Marmoritaivas' }, function(err, node) {
  // this code is not reached until `txn.commit` is called
  // node -> { id: 1, title: 'Marmoritaivas' }
});

txn.commit();

Can I reference newly created nodes?

Yes! Calling, for example, node.save will synchronously return a special object which you can use to refer to that newly created node within the batch.

For example, this is perfectly valid in the context of a batch transaction:

var txn = db.batch();

var singer = txn.save({name: 'Johanna Kurkela'});
var album = txn.save({title: 'Kauriinsilmät', year: 2008});
var performance = txn.relate(singer, 'performs_on', album, {role: 'Primary Artist'});
txn.rel.index('performances', performance, 'year', '2008');

txn.commit(function(err, results) {});

I didn't use any callbacks. How can I find my results when the batch is done?

Each function you call on the batch object will return a special object that you can use to refer to that call's results once that batch is finished (in addition to the intra-batch referencing feature mentioned above). The best way to demonstrate this is by example:

var txn = db.batch();

var album = txn.save({title: 'Hetki Hiljaa'});
var songs = txn.save([
  { title: 'Olen Sinussa', length: 248 },
  { title: 'Juurrun Tähän Ikävään', length: 271 }
]);
// note we can also use `songs` to reference the node that will be created
txn.relate(album, 'has_song', songs[0], { trackNumber: 1 });
txn.relate(album, 'has_song', songs[1], { trackNumber: 3 });

txn.commit(function(err, results) {
  var album = results[album]; // album -> { title: 'Hetki Hiljaa', id: 1 }
  var tracks = results[songs];
  /* tracks -> [{ title: 'Olen Sinussa', length: 248, id: 2 },
                { title: 'Juurrun Tähän Ikävään', length: 271, id: 3}] */
});

What happens if one of the operations fails?

Then no changes are made. Neo4j's batch transactions are atomic, so if one operation fails, then no changes to the database are made. Neo4j's own documentation has the following to say:

This service is transactional. If any of the operations performed fails (returns a non-2xx HTTP status code), the transaction will be rolled back and all changes will be undone.

Can I nest batches?

No, as of now we don't support nesting batches as it tends to confuse the intra-batch referencing functionality. To enforce this, you'll find that the seraph-like object returned by db.batch() has no .batch function itself.

How can I tell if this db object is a batch operation?

Like so:

// db.isBatch -> undefined
var txn = db.batch();
// txn.isBatch -> true
if (txn.isBatch) // Woo! I'm in a batch.

Node Operations

save(object, [key, value,] callback)

Aliases: node.save

Create or update a node. If object has an id property, the node with that id is updated. Otherwise, a new node is created. Returns the newly created/updated node to the callback.

Arguments

  • node - an object to create or update
  • key, value (optional) - a property key and a value to update it with. This allows you to only update a single property of the node, without touching any others. If key is specified, value must also be.
  • callback - function(err, node). node is the newly saved or updated node. If a create was performed, node will now have an id property. The returned object is not the same reference as the passed object (the passed object will never be altered).

Example

// Create a node
db.save({ name: 'Jon', age: 22, likes: 'Beer' }, function(err, node) {
  console.log(node); // -> { name: 'Jon', age: 22, likes: 'Beer', id: 1 }

  // Update it
  delete node.likes;
  node.age++;
  db.save(node, function(err, node) {
    console.log(node); // -> { name: 'Jon', age: 23, id: 1 }
  })
})

node.saveUnique(node, index, key, value, [returnExistingOnConflict = false,] callback)

Save a node, using an index to enforce uniqueness.

See also node.index.saveUniqueOrFail & node.index.getOrSaveUnique.

Arguments

  • node - an object to create or update
  • index - the index in which key and value are relevant
  • key - the key under which to index this node and enforce uniqueness
  • value - the value under which to index this node and enforce uniqueness
  • returnExistingOnConflict (optional, default=false) - what to do when there is a conflict (when the index you specified already refers to a node). If set to true, the node that the index currently refers to is returned. Otherwise, an error is return indicating that there was a conflict (you can check this by testing err.statusCode == 409.
  • callback - function(err, node) - node is the newly created node or the node that was in the specified index, depending on returnExistingOnConflict.

Example

db.saveUnique({name: 'jon'}, 'people', 'name', 'jon', function(err, node) {
  //node = { name: 'jon', id: 1 }
  db.saveUnique({age: 24}, 'people', 'name', 'jon', function(err, node) {
    //err.statusCode == 409, because there was already a node indexed under
    //people(name="jon").
  });

  db.saveUnique({location:'Bergen'}, 'people', 'name', 'jon', true, function(err, node) {
    // node = {name: 'jon', id: 1}
    // because there was node already indexed under people(name="jon") and we 
    // specified that we wanted that node returned on the event of a conflict.
  });
});

read(id|object, [property,] callback)

Aliases: node.read

Read a node.

Note: If the node doesn't exist, Neo4j will return an exception. You can check if this is indicating that your node doesn't exist because err.statusCode will equal 404. This is inconsistent with behaviour of node.index.read, but it is justified because the Neo4j REST api behaviour is inconsistent in this way as well.

Arguments

  • id | object - either the id of the node to read, or an object containing an id property of the node to read.
  • property (optional) - the name of the property to read. if this is specified, only the value of this property on the object is returned.
  • callback - function(err, node). node is an object containing the properties of the node with the given id.

Example

db.save({ make: 'Citroen', model: 'DS4' }, function(err, node) {
  db.read(node.id, function(err, node) {
    console.log(node) // -> { make: 'Citroen', model: 'DS4', id: 1 }
  })
})

delete(id|object, [force | property], [callback])

Aliases: node.delete

Delete a node.

Arguments

  • id | object - either the id of the node to delete, or an object containing an id property of the node to delete.
  • force (optional - default = false) - if truthy, will delete all the node's relations prior to deleting the node.
  • property (optional) - if specified, delete only the property with this name on the object. note that you can either specify property or force, not both, as force is meaningless when deleting a property
  • callback - function(err). if err is falsy, the node has been deleted.

Example

db.save({ name: 'Jon' }, function(err, node) {
  db.delete(node, function(err) {
    if (!err) console.log('Jon has been deleted!');
  })
})

find(predicate, [any, [start,]] callback)

Aliases: node.find

Perform a query based on a predicate. The predicate is translated to a cypher query.

Arguments

Example

Given database content:

{ name: 'Jon'    , age: 23, australian: true  }
{ name: 'Neil'   , age: 60, australian: true  }
{ name: 'Belinda', age: 26, australian: false }
{ name: 'Katie'  , age: 29, australian: true  }

Retrieve all australians:

var predicate = { australian: true };
var people = db.find(predicate, function (err, objs) {
    if (err) throw err;
    assert.equals(3, people.length);
};

relationships(id|object, [direction, [type,]] callback)

*Aliases: node.relationships

Read the relationships involving the specified node.

Arguments

  • id | object - either the id of a node, or an object containing an id property of a node.
  • direction ('all'|'in'|'out') (optional unless type is passed, default='all') - the direction of relationships to read.
  • type (optional, default='' (match all relationships)) - the relationship type to find
  • callback - function(err, relationships) - relationships is an array of the matching relationships

Example

db.relationships(452, 'out', 'knows', function(err, relationships) {
  // relationships = all outgoing `knows` relationships from node 452
})

Relationship Operations

rel.create(firstId|firstObj, type, secondId|secondobj, [properties], callback)

Aliases: relate, node.relate

Create a relationship between two nodes.

Arguments

  • firstId | firstObject - id of the start node or an object with an id property for the start node
  • type - the name of the relationship
  • secondId | secondObject - id of the end node or an object with an id property for the end node
  • properties (optional, default={}) - properties of the relationship
  • callback - function(err, relationship) - relationship is the newly created relationship

Example

db.relate(1, 'knows', 2, { for: '2 months' }, function(err, relationship) {
  assert.deepEqual(relationship, {
    start: 1,
    end: 2,
    type: 'knows',
    properties: { for: '2 months' },
    id: 1
  });
});

rel.createUnique(firstId|firstObj, type, secondId|secondObj, [properties,] index, key, value, [returnExistingOnConflict = false,] callback)

Create a relationship between two nodes, using an index to enforce uniqueness.

See also rel.index.saveUniqueOrFail & rel.index.getOrSaveUnique.

Arguments

  • firstId | firstObject - id of the start node or an object with an id property for the start node
  • type - the name of the relationship
  • secondId | secondObject - id of the end node or an object with an id property for the end node
  • properties (optional, default={}) - properties of the relationship
  • index - the index in which key and value are relevant
  • key - the key under which to index this relationship and enforce uniqueness
  • value - the value under which to index this relationship and enforce uniqueness
  • returnExistingOnConflict (optional, default=false) - what to do when there is a conflict (when the index you specified already refers to a relationship). If set to true, the relationship that the index currently refers to is returned. Otherwise, an error is return indicating that there was a conflict (you can check this by testing err.statusCode == 409.
  • callback - function(err, relationship) - relationship is the newly created relationship or the relationship that was in the specified index, depending on returnExistingOnConflict

Example

db.rel.createUnique(1, 'knows', 2, 'friendships', 'type', 'super', function(err, rel) {
  // rel = {start: 1, end: 2, type: 'knows', properties: {}, id = 1}
  db.rel.createUnique(1, 'knows', 2, 'friendships', 'type', 'super', function(err, node) {
    //err.statusCode == 409, because there was already a relationship indexed under
    //friendships(type="super").
  });

  db.rel.createUnique(1, 'knows', 2, 'friendships', 'type', 'super', true, function(err, node) {
    // rel = {start: 1, end: 2, type: 'knows', properties: {}, id = 1}
    // no new index was created, the first one was returned - because there was
    // already a relationship indexed under friendships(type="super") and we
    // specified that on the event of a conflict we wanted the indexed rel to 
    // be returned
  });
});

rel.update(relationship, [key, value,] callback)

Update the properties of a relationship. Note that you cannot use this method to update the base properties of the relationship (start, end, type) - in order to do that you'll need to delete the old relationship and create a new one.

Arguments

  • relationship - the relationship object with some changed properties
  • key, value (optional) - if a key and value is specified, only the property with that key will be updated. the rest of the object will not be touched.
  • callback - function(err). if err is falsy, the update succeeded.

Example

var props = { for: '2 months', location: 'Bergen' };
db.rel.create(1, 'knows', 2, props, function(err, relationship) {
  delete relationship.properties.location;
  relationship.properties.for = '3 months';
  db.rel.update(relationship, function(err) {
    // properties on this relationship in the database are now equal to
    // { for: '3 months' }
  });
});

rel.read(object|id, callback)

Read a relationship.

Arguments

  • object | id - the id of the relationship to read or an object with an id property of the relationship to read.
  • callback - function(err, relationship). relationship is an object representing the read relationship.

Example

db.rel.create(1, 'knows', 2, { for: '2 months' }, function(err, newRelationship) {
  db.rel.read(newRelationship.id, function(err, readRelationship) {
    assert.deepEqual(newRelationship, readRelationship);
    assert.deepEqual(readRelationship, {
      start: 1,
      end: 2,
      type: 'knows',
      id: 1,
      properties: { for: '2 months' }
    });
  });
});

rel.delete(object|id, [callback])

Delete a relationship.

Arguments

  • object | id - the id of the relationship to delete or an object with an id property of the relationship to delete.
  • callback - function(err). If err is falsy, the relationship has been deleted.

Example

db.rel.create(1, 'knows', 2, { for: '2 months' }, function(err, rel) {
  db.rel.delete(rel.id, function(err) {
    if (!err) console.log("Relationship was deleted");
  });
});

Index Operations

node.index.create(name, [config,] callback)

rel.index.create(name, [config,] callback)

Create a new index. If you're using the default index configuration, this method is not necessary - you can just start using the index with index.add as if it already existed.

NOTE for index functions: there are two different types on index in neo4j - node indexes and relationship indexes. When you're working with node indexes, you use the functions on node.index. Similarly, when you're working on relationship indexes you use the functions on rel.index. Most of the functions on both of these are identical (excluding the uniqueness functions), but one acts upon node indexes, and the other upon relationship indexes.

Arguments

  • name - the name of the index that is being created
  • config (optional, default={}) - the configuration of the index. See the neo4j docs for more information.
  • callback - function(err). If err is falsy, the index has been created.

Example

var indexConfig = { type: 'fulltext', provider: 'lucene' };
db.node.index.create('a_fulltext_index', indexConfig, function(err) {
  if (!err) console.log('a fulltext index has been created!');
});

node.index.add(indexName, id|object, key, value, callback);

rel.index.add(indexName, id|object, key, value, callback);

node.index.add is aliased as node.index & index

Add a node/relationship to an index.

NOTE for index functions: there are two different types on index in neo4j - node indexes and relationship indexes. When you're working with node indexes, you use the functions on node.index. Similarly, when you're working on relationship indexes you use the functions on rel.index. Most of the functions on both of these are identical (excluding the uniqueness functions), but one acts upon node indexes, and the other upon relationship indexes.

Arguments

  • indexName - the name of the index to add the node/relationship to.
  • id | object - the id of the node/relationship to add to the index or an object with an id property of the node/relationship to add to the index.
  • key - the key to index the node/relationship with
  • value - the value to index the node/relationship with
  • callback - function(err). If err is falsy, the node/relationship has been indexed.

Example

db.save({ name: 'Jon', }, function(err, node) {
  db.index('people', node, 'name', node.name, function(err) {
    if (!err) console.log('Jon has been indexed!');
  });
});

node.index.read(indexName, key, value, callback);

rel.index.read(indexName, key, value, callback);

Read the object(s) from an index that match a key-value pair. See also index.readAsList.

NOTE for index functions: there are two different types on index in neo4j - node indexes and relationship indexes. When you're working with node indexes, you use the functions on node.index. Similarly, when you're working on relationship indexes you use the functions on rel.index. Most of the functions on both of these are identical (excluding the uniqueness functions), but one acts upon node indexes, and the other upon relationship indexes.

Arguments

  • indexName - the index to read from
  • key - the key to match
  • value - the value to match
  • callback - function(err, results). results is a node or relationship object (or an array of them if there was more than one) that matched the given key-value pair in the given index. If nothing matched, results === false. index.readAsList is similar, but always gives results as an array, with zero, one or more elements.

Example

db.rel.index.read('friendships', 'location', 'Norway', function(err, rels) {
  // `rels` is an array of all relationships indexed in the `friendships`
  // index, with a value `Norway` for the key `location`.
});

node.index.readAsList(indexName, key, value, callback);

rel.index.readAsList(indexName, key, value, callback);

Read the object(s) from an index that match a key-value pair. See also index.read.

NOTE for index functions: there are two different types on index in neo4j - node indexes and relationship indexes. When you're working with node indexes, you use the functions on node.index. Similarly, when you're working on relationship indexes you use the functions on rel.index. Most of the functions on both of these are identical (excluding the uniqueness functions), but one acts upon node indexes, and the other upon relationship indexes.

Arguments

  • indexName - the index to read from
  • key - the key to match
  • value - the value to match
  • callback - function(err, results). results is an array of node or relationship objects that matched the given key-value pair in the given index. index.read is similar, but gives results as false, an object or an array of objects depending on the number of hits.

Example

db.rel.index.readAsList('friendships', 'location', 'Norway', function(err, rels) {
  // `rels` is an array of all relationships indexed in the `friendships`
  // index, with a value `Norway` for the key `location`.
});

node.index.remove(indexName, id|object, [key, [value,]] callback);

rel.index.remove(indexName, id|object, [key, [value,]] callback);

Remove a node/relationship from an index.

NOTE for index functions: there are two different types on index in neo4j - node indexes and relationship indexes. When you're working with node indexes, you use the functions on node.index. Similarly, when you're working on relationship indexes you use the functions on rel.index. Most of the functions on both of these are identical (excluding the uniqueness functions), but one acts upon node indexes, and the other upon relationship indexes.

Arguments

  • indexName - the index to remove the node/relationship from.
  • id | object - the id of the node/relationship to remove from the index or an object with an id property of the node/relationship to remove from the index.
  • key (optional) - the key from which to remove the node/relationship. If none is specified, every reference to the node/relationship is deleted from the index.
  • value (optional) - the value from which to remove the node/relationship. If none is specified, every reference to the node/relationship is deleted for the given key.
  • callback - function(err). If err is falsy, the specified references have been removed.

Example

db.node.index.remove('people', 6821, function(err) {
  if (!err) console.log("Every reference of node 6821 has been removed from the people index");
});

db.rel.index.remove('friendships', 351, 'in', 'Australia', function(err) {
  if (!err) console.log("Relationship 351 is no longer indexed as a friendship in Australia");
})

node.index.delete(name, callback);

rel.index.delete(name, callback);

Delete an index.

NOTE for index functions: there are two different types on index in neo4j - node indexes and relationship indexes. When you're working with node indexes, you use the functions on node.index. Similarly, when you're working on relationship indexes you use the functions on rel.index. Most of the functions on both of these are identical (excluding the uniqueness functions), but one acts upon node indexes, and the other upon relationship indexes.

Arguments

  • name - the name of the index to delete
  • callback - function(err). if err is falsy, the index has been deleted.

Example

db.rel.index.delete('friendships', function(err) {
  if (!err) console.log('The `friendships` index has been deleted');
})

node.index.getOrSaveUnique(node, index, key, value, callback);

rel.index.getOrSaveUnique(startNode, relName, endNode, [properties,] index, key, value, callback);

Save a node or relationship, using an index to enforce uniqueness. If there is already a node or relationship saved under the specified key and value in the specified index, that node or relationship will be returned.

Note that you cannot use this function to update nodes.

NOTE for index functions: there are two different types on index in neo4j - node indexes and relationship indexes. When you're working with node indexes, you use the functions on node.index. Similarly, when you're working on relationship indexes you use the functions on rel.index. Most of the functions on both of these are identical (excluding the uniqueness functions), but one acts upon node indexes, and the other upon relationship indexes.

Arguments (node)

  • node - the node to save
  • index - the name of the index in which key and value are relevant
  • key - the key to check or store under
  • value - the value to check or store under
  • callback - function(err, node) - returns your saved node, or the node that was referenced by the specified key and value if one already existed.

Arguments (relationship)

  • startNode - the start point of the relationship (object containing id or id)
  • relName - the name of the relationship to create
  • endNode - the end point of the relationship (object containing id or id)
  • properties (optional) - an object containing properties to store on the created relationship.
  • index - the name of the index in which key and value are relevant
  • key - the key to check or store under
  • value - the value to check or store under
  • callback - function(err, rel) - returns your created relationship, or the relationship that was referenced by the specified key and value if one already existed.

Example

var tag = { name: 'finnish' };
db.node.index.getOrSaveUnique(tag, 'tags', 'name', tag.name, function(err, tag) {
  // tag == { id: 1, name: 'finnish' }

  // save another new object with the same properties
  db.node.index.getOrSaveUnique({name: 'finnish'}, 'tags', 'name', 'finnish', function(err, newTag) {
    // newTag == { id: 1, name: 'finnish' }
    // no save was performed because there was already an object at that index
  });
});

node.index.saveUniqueOrFail(node, index, key, value, callback);

rel.index.saveUniqueOrFail(startNode, relName, endNode, [properties,] index, key, value, callback);

Save a node or relationship, using an index to enforce uniqueness. If there is already a node or relationship saved under the specified key and value in the specified index, an error is returned indicating that there as a conflict. You can check if the result was a conflict by checking if err.statusCode == 409.

NOTE for index functions: there are two different types on index in neo4j - node indexes and relationship indexes. When you're working with node indexes, you use the functions on node.index. Similarly, when you're working on relationship indexes you use the functions on rel.index. Most of the functions on both of these are identical (excluding the uniqueness functions), but one acts upon node indexes, and the other upon relationship indexes.

Arguments (node)

  • node - the node to save
  • index - the name of the index in which key and value are relevant
  • key - the key to check or store under
  • value - the value to check or store under
  • callback - function(err, node) - returns your created node, or an err with statusCode == 409 if a node already existed at that index

Arguments (relationship)

  • startNode - the start point of the relationship (object containing id or id)
  • relName - the name of the relationship to create
  • endNode - the end point of the relationship (object containing id or id)
  • properties (optional) - an object containing properties to store on the created relationship.
  • index - the name of the index in which key and value are relevant
  • key - the key to check or store under
  • value - the value to check or store under
  • callback - function(err, rel) - returns your created relationship, or an err with statusCode == 409 if a relationship already existed at that index

Example

var tag = { name: 'finnish' };
db.node.index.saveUniqueOrFail(tag, 'tags', 'name', tag.name, function(err, tag) {
  // tag == { id: 1, name: 'finnish' }

  // save another new object with the same properties
  db.node.index.saveUniqueOrFail({name: 'finnish'}, 'tags', 'name', 'finnish', function(err, newTag) {
    // newTag == undefined
    // err.statusCode == 409 (conflict)
    // an error was thrown because there was already a node at that index.
  });
});

Development of Seraph is lovingly sponsored by BRIK Tekonologier AS in Bergen, Norway.

Jump to Line
Something went wrong with that request. Please try again.