I am working on an application where Neo4j data is being updated for multiple clients in realtime. The times on the different client machines may be different, so any timestamps need to be set by the Neo4j database itself.
What possibilities does the Neo4j REST API provide for running TIMESTAMP() locally and inserting it into a field?
I know that I can create a query like...
WITH TIMESTAMP() AS timestamp
MATCH (node)
WHERE id(node) = {id}
SET node.updatedAt = timestamp
, node.property = "new value"
RETURN node
... and use a transaction to execute it on the remote server. But is this the only solution? Are there ways to use the Node Properties URI so that the database will create the appropriate values dynamically?
Neo4j REST API is very limited in this case. As you mentioned you can use Cypher REST endpoint and set that value manually.
Another option is to writer your own Neo4j Unmanaged Extension, which will use Transaction Event API. It's similar to stored-procedures.
Here is very good article how to write that Extension by using GraphAware Framework - http://graphaware.com/neo4j/transactions/2014/07/11/neo4j-transaction-event-api.html
Also here is simple real-world example that kind of Extension - https://github.com/graphaware/neo4j-uuid
Related
I'm new to neo4j and graph databases in general.
Given a complex Cypher query, that I don't want to store inside the application (or several applications), but keep centralized, what options are left to me?
In a SQL database I would use a stored function. Are UDF function the way to go in neo4j?
From the docs it seems to me that they're more a way to extend the database functionality by being able to access the graph internals, but I've just started studying them.
Take a look at the custom functions and procedures available in the apoc library.
https://neo4j.com/docs/labs/apoc/current/cypher-execution/cypher-based-procedures-functions/
CALL apoc.custom.asProcedure('answer','RETURN 42 as answer')
CALL custom.answer() YIELD row RETURN row.answer
I am trying to figure out how to identify a database uniquely via a cypher query. I understand the StoreID along with the KernelStartTime kernel parameters with do this... can I access those parameters or something else via a cypher query?
The Cypher language currently only exposes the graph data, not metadata about the DB instance.
As a workaround, you may want to store uniquely identifying information in a singleton node (i.e., a node that is the only one having a special label) in each DB instance. This tactic will not work, however, if you want to use Cypher to distinguish between the DB instances in a HA cluster.
While technically I'm not sure if this is strictly a Cypher query or not, it is possible by querying the jmx interface through Cypher. Try this:
CALL dbms.queryJmx("org.neo4j:instance=*,name=Kernel") YIELD attributes
RETURN attributes.StoreId.value, attributes.KernelStartTime.value
Or this to list all jmx objects:
CALL dbms.queryJmx("org.neo4j:*")
TL,DR: I need a query which gives me all nodes/relationships which contain a certain value (in my case a string, so much I know), without knowing which property(key) contains the string. I am using neo4j(latest version), meteor (latest version) and the meteor neo4j driver, which is recommended on the neo4j website for meteor.
Currently I am working (as part of my bachelor thesis) on a tool to visualize the output of any Cypher query on any database, regardless of the database contents.
So far I've managed to correctly display nodes/relationships which are coming out. My problem now is to visualize (get nodes and relationships to feed into my frontend) textual queries like (taken from the neo4j movie database, which I am using for development)
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors)
RETURN coActors.name
This kind of queries only returns an array of strings and not whole nodes or relationships. I now need some way (preferably a Cypher query) to get all nodes which contain for example the string "Audrey Tatou".
The problem I've now run into is that I didn't find a way to write a query which doesn't need something like
MATCH n
WHERE Person.name = "some name"
Since I don't know anything about the contents of the database I cannot use
WHERE propertyName = "propertyValue"
since I only know the value but not the name of the property.
The only solution here will be to get every nodes with your label and check properties and values using reflection on client side.
Using cypher, the solution would be to get all properties and their values and parse their values using a foreach loop. Maybe you can do this, but I'm really not sure, it's a recent feature but you can still give a try.
Here is what I found for the cypher solution: How can I return all properties for a node using Cypher?
So, you have query that returns array of string.
In fact - you can receive almost anything as result. Cypher is capable to return just bare strings, that are not related to anything.
Long story short - you can't vizualize this data, because of this data nature. Best you can do is to represent them as table (or similar), like Neo4j browser do this.
But, there is (probably) solution for you. Neo4j has feature called Legacy indexing. And there you can find full text indexes. Maybe this can help you.
You can just use a driver that returns nodes and rels, or if you do the queries manually add resultDataContents entry
{statements:[{statement:"MATCH ..","resultDataContents",["graph"]}]}
to your payload and you get nodes and relationships back.
As far as I understand it the IDs given by Neo4j (ID(node)) are unstable and behave somewhat like row numbers in SQL. Since IDs are mostly used for relations in SQL and these are easily modeled in Neo4j, there doesn't seem to be much use for IDs, but then how do you solve retrieval of specific nodes? Having a REST API which is supposed to have unique routes for each node (e.g. /api/concept/23) seems like a pretty standard case for web applications.
But despite it being so fundamental, the only viable way I found were either via
language specific frameworks
as an unconnected node which maintains the increments:
// get unique id
MERGE (id:UniqueId{name:'Person'})
ON CREATE SET id.count = 1
ON MATCH SET id.count = id.count + 1
WITH id.count AS uid
// create Person node
CREATE (p:Person{id:uid,firstName:'Gabriel',lastName:'Smith'})
RETURN p AS person
Source: http://www.neo4j.org/graphgist?8012859
Is there really not a simpler way and if not, is there a particular reason for it? Is my approach an anti-pattern in the context of Neo4j?
Neo4j internal ids are a bit more stable than sql row id's as they will never change during a transaction for e.g.
And indeed exposing them for external usage is not recommended. I know there are some intentions at Neo internals to implement such a feature.
Basically people tend to use two solutions for this :
Using a UUID generator at the application level like for PHP : https://packagist.org/packages/rhumsaa/uuid and add a label/uuid unique constraint on all nodes.
Using a very handful Neo4j plugin like https://github.com/graphaware/neo4j-uuid that will add uuid properties on the fly, so it remove you the burden to handle it at the application level and it is easier to manage the persistence state of your node objects
I agree with Pavel Niedoba.
I came up with this without and UniqueID Node:
MATCH (a:Person)
WITH a ORDER BY a.id DESC LIMIT 1
CREATE (n:Person {id: a.id+1})
RETURN n
It requires a first Node with an id field though.
Consider the Neo4J 2.0 Cypher query
MERGE (u:User {id_str:"123"})
ON CREATE
SET {giant_params_string_from_twitter_api}
ON MATCH
SET u.lastSeen = timestamp()
RETURN u
Here I've downloaded the user's metadata from Twitter, and if the user doesn't exist, then I insert all of his metadata. If the user already exists, then I just modify his timestamp.
The call out to Twitter API needed to retrieve the params is long and expensive (especially when you consider that I keep getting rate limited). And a lot of time the node already exists in the database. Here's what would rather do:
MERGE (u:User {id_str:"123"})
ON CREATE
SET get_twitter_params("123")
ON MATCH
SET u.lastSeen = timestamp()
RETURN u
In ON CREATE I would like to somehow link back out to a callback to pull down this data.
Is there any way to call create my own function to be used in Cypher?
Not yet! They're considering ways of implementing user defined functions (UDFs), though, so I don't think it will be too far out.
You might consider checking for existence before making your request to the twitter, if that is the expensive call--unfortunately you'd have to do that outside of your single Cypher request.
As of Neo4j 3.0, you can now write your own functions. They are however written in Java.
Look into this link for more details: https://neo4j.com/developer/procedures-functions/