This question already has answers here:
How to hide unwanted relationships between nodes in Neo4j
(2 answers)
Closed 5 years ago.
I have created a small database with three nodes, Abraham, Isaac and Jacob. Abraham is Isaac's FATHER, and Isaac is Jacob's FATHER.
Now I perform the following query:
MATCH (a:Person), (i:Person)
WHERE a.name='Abraham' and i.name='Isaac'
RETURN a, i
Running the query from the Neo4J web interface shows the two nodes with the FATHER relationship between them:
This is strange, as I have not requested any relationships. The JSON response doesn't contain the relationships, either:
[{
"keys": [
"a",
"i"
],
"length": 2,
"_fields": [
{
"identity": {
"low": 0,
"high": 0
},
"labels": [
"Person"
],
"properties": {
"name": "Abraham"
}
},
{
"identity": {
"low": 1,
"high": 0
},
"labels": [
"Person"
],
"properties": {
"name": "Isaac"
}
}
],
"_fieldLookup": {
"a": 0,
"i": 1
}
}]
Why is Neo4J showing this relationship? And how can I make it stop? I'm trying to create a query that returns various relationships between a set of nodes, and I really don't want Neo4J interfering and adding its own relationships.
It just the way the Neo4j browser visualizes, nothing more. Since you've got both nodes, Neo4j has everything it needs (the pointers) to know that there is a relationship (and shows it). If you process the result programmatically (in Java or such ... as you're bound to do since I assume the Neo4j browser will not be the "production" result) you will be able to process the results as you wish. If you're only interested in the names and not the actual nodes, just do
MATCH (a:Person), (i:Person)
WHERE a.name='Abraham' and i.name='Isaac'
RETURN a.name, i.name
Hope this helps.
Regards,
Tom
Related
Is there any way to use a multi-layer map in Highcharts? In my case, I need three layers: One for the countries, one for the borders (which show the disputed ones differently than the normal ones) and one for the lakes, like this:
In the moment, I don't see how this could be achieved. Or can I export the three layers from shapefile to JSON and then stick the three together? But would a »join« in order to color the countries still work?
Thanks for any hints.
According to the comments - something, like is required on the image, can be done by base on this official demo: https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/maps/demo/mapline-mappoint
After some attempts, #luftikus143 face into the issue that geometry can't be set as null in his custom JSON file and my solution is to assign it as an object with the empty coordinates array. Demo: jsfiddle.net/BlackLabel/06xvrs8m/1
{
"type": "Feature",
"geometry": {
type: 'polygon',
"coordinates": [
[
]
]
},
"properties": {
"OBJECTID": 1,
"NAME": "Great Bear Lake",
"Shape_Leng": 35.7525061159,
"Shape_Area": 6.12829979344
}
},
Let's say that I'm making a Cloudant database to store all the service records for my fleet of cars (I'm not, but the problem is pretty much the same.) To do this, I have two types of records:
Cars:
{
"type": "Car",
"_id": "VIN 1",
"plateNumber": "ecto-1",
"plateState": "NY",
"make": "Cadillac",
"model": "Professional Chassis",
"year": 1959
}
{
"type": "Car",
"_id": "VIN 2",
"plateNumber": "mntclmbr",
"plateState": "VT",
"make": "Jeep",
"model": "Wrangler",
"year": 2016
}
And service records:
{
"type": "ServiceRecord",
"_id": "service1",
"carServiced": "VIN 1",
"date": [1984, 6, 8],
"item": "Cleaning (Goo)",
"cost": 300
}
{
"type": "ServiceRecord",
"_id": "service2",
"carServiced": "VIN 1",
"date": [1984, 6, 9],
"item": "Cleaning (Marshmellow)",
"cost": 800
}
{
"type": "ServiceRecord",
"_id": "service3",
"carServiced": "VIN 2",
"date": [2016, 4, 2],
"item": "Alignment",
"cost": 150
}
There's a couple things to note about how this works:
The VIN number of a car will never change is used as the document _id.
The service records for a car should not be lost if the car is registered in a new state, or with a new plate number.
Due to the volume of cars, and how often they need repairs, it's not reasonable to edit a car's document if a service record needs to be added, removed, or changed.
Currently, I have a couple views to look up information.
First, I've got a map from license plate to VIN:
function(doc){
if (doc.type == "Car"){
emit([doc.plateState, doc.plateNumber], doc._id);
}
}
// Results in:
["NY", "ecto-1"] -> "VIN 1"
["VT", "mntclmbr"] -> "VIN 2"
Second, I've got a map map from all the cars' VINs to the service records:
function(doc){
if (doc.type == "ServiceRecord"){
emit(doc.carServiced, doc);
}
}
// Results in:
"VIN 1" -> {"_id": "service1", ...}
"VIN 1" -> {"_id": "service2", ...}
"VIN 2" -> {"_id": "service3", ...}
Finally, I've got a map map from all the cars' VINs and service dates to the specific service that happened on that date:
function(doc){
if (doc.type == "ServiceRecord"){
var key = [doc.carServiced, doc.date[0], doc.date[3], doc.date[2]];
emit(key, doc);
}
}
// Results in:
["VIN 1", 1984, 6, 8] -> {"_id": "service1", ...}
["VIN 1", 1984, 6, 9] -> {"_id": "service2", ...}
["VIN 2", 2016, 4, 2] -> {"_id": "service3", ...}
With these three maps, I can find three different things:
The VIN of any car by its license plate.
The service records of any car by its VIN.
The service records of any car by its VIN for any particular year, month, or day.
However, can't find all the service records of a car by its license plate. (At least not in one step.) To do that, I would need a map like this:
["NY", "ecto-1"] -> {"_id": "service1", ...}
["NY", "ecto-1"] -> {"_id": "service2", ...}
["VT", "mntclmbr"] -> {"_id": "service3", ...}
And to make it even MORE complicated, I'd like to be able to look up service records by license plate AND date, with a map like this:
["NY", "ecto-1", 1984, 6, 8] -> {"_id": "service1", ...}
["NY", "ecto-1", 1984, 6, 9] -> {"_id": "service2", ...}
["VT", "mntclmbr", 2016, 4, 2] -> {"_id": "service3", ...}
Unfortunately, I don't know how to generate maps like these because the key requires information from two documents. I can only get plate information from Car documents and I can only get service information (including the document _id for the value of emit) from ServiceRecord documents.
So far, my only thought is to do two queries: one to get the VIN from the plate info, and another to get the service records from the VIN. They'll be fast queries, so it's not a huge problem, but I feel like there's a better way.
Anyone know what that better way might be?
(Bonus: The two-query method does not allow for finding all service records by state in an efficient way. The last map I describe would be able to do that. So bonus internet-points for anyone who can describe a solution that provides that functionality as well.)
**Edit: Another issue, here, was suggested as a possible duplicate. It is definitely a similar problem, however the solutions provided do not solve this issue. Specifically, the top solution suggests storing an document's position within the tree. In this case, that would be something like "index":[State, Number, Year, Month, Day]" in a ServiceRecord document. However, we can't do that because the plate information can easily change.
Hopefully you are still around. The gist of the answer is : in CouchDb when you feel a need to do joins you are 99% of the times doing something wrong. What you need to do is have all the information you need in one document.
You need to get into the habit of thinking about how you are going to query your data when you design what to save. You will find that replacing the "relational normalization" habit with this habit is healthy.
What you can do here is save the licence plate number in the service record document. Don't be afraid to denormalize. A service record should therefore look like this :
{
"type": "ServiceRecord",
"_id": "service3",
"carServiced": "VIN 2",
"carPlateNumber": "mntclmbr",
"date": [2016, 4, 2],
"item": "Alignment",
"cost": 150
}
And you can easily do whatever you want from here. That being said, the architect I am can smell that you are likely to invent new ways to query this data every month. For this reason, I'd personally prefer to store the whole car document within the service record :
{
"type": "ServiceRecord",
"_id": "service3",
"carServiced": {
"type": "Car",
"_id": "VIN 2",
"plateNumber": "mntclmbr",
"plateState": "VT",
"make": "Jeep",
"model": "Wrangler",
"year": 2016
},
"date": [2016, 4, 2],
"item": "Alignment",
"cost": 150
}
This is absolutely fine. Especially since a service record is a snapshot in time and you do not need to worry about updating the information. I actually find that this is one of the scenarios where CouchDb particularly shines as storing a snapshot basically is a free lunch (as opposed to managing a cars_snapshot table in a relational system). And we tend to forget it but very often (especially as far as sales are concerned), we are interested in snapshots, not up-to-date relational data (what was the customer name at the time he bought, what was the tax rate at the time he bought, etc.). But relational systems put us in the "most up to date by default" habit because snapshot management involves a significant overhead there.
The bottom line is that this kind of denormalization is absolutely fine in CouchDb. You are in the intended usage and won't be bitten in the back down the road. As CouchDb puts it : just relax ;)
It sounds like chained mapreduce could provide your solution?
https://examples.cloudant.com/sales/_design/sales/index.html
I noticed for some queries the response populates the "graph" section as follows
}
],
"graph": {
"nodes": [
{
"id": "68",
"labels": [
"ROOM"
],
"properties": {
"id": 15,
"name": "Sun and Snow",
but for other queries, this "graph" section is not returning with nodes/relationships and associated labels/properties even though the "data" section returns valid output
Does it convey anything about the quality of the cypher query ?
It depends on what you return from your query. If you return nodes and relationships, you'll get a graph. If you return scalars such as n.name or r.weight, you don't get a graph.
Are you talking about the HTTP requests from the web UI or requests that you are making yourself?
The graph key is controlled via the resultDataContents option when making a request. You can see the documentation for that here:
http://neo4j.com/docs/stable/rest-api-transactional.html#rest-api-return-results-in-graph-format
You can request multiple formats for the result ("row" and "REST" are other examples)
I'm currently using the example data on console.neo4j.org to write a query that outputs hierarchical JSON.
The example data is created with
create (Neo:Crew {name:'Neo'}), (Morpheus:Crew {name: 'Morpheus'}), (Trinity:Crew {name: 'Trinity'}), (Cypher:Crew:Matrix {name: 'Cypher'}), (Smith:Matrix {name: 'Agent Smith'}), (Architect:Matrix {name:'The Architect'}),
(Neo)-[:KNOWS]->(Morpheus), (Neo)-[:LOVES]->(Trinity), (Morpheus)-[:KNOWS]->(Trinity),
(Morpheus)-[:KNOWS]->(Cypher), (Cypher)-[:KNOWS]->(Smith), (Smith)-[:CODED_BY]->(Architect)
The ideal output is as follows
name:"Neo"
children: [
{
name: "Morpheus",
children: [
{name: "Trinity", children: []}
{name: "Cypher", children: [
{name: "Agent Smith", children: []}
]}
]
}
]
}
Right now, I'm using the following query
MATCH p =(:Crew { name: "Neo" })-[q:KNOWS*0..]-m
RETURN extract(n IN nodes(p)| n)
and getting this
[(0:Crew {name:"Neo"})]
[(0:Crew {name:"Neo"}), (1:Crew {name:"Morpheus"})]
[(0:Crew {name:"Neo"}), (1:Crew {name:"Morpheus"}), (2:Crew {name:"Trinity"})]
[(0:Crew {name:"Neo"}), (1:Crew {name:"Morpheus"}), (3:Crew:Matrix {name:"Cypher"})]
[(0:Crew {name:"Neo"}), (1:Crew {name:"Morpheus"}), (3:Crew:Matrix {name:"Cypher"}), (4:Matrix {name:"Agent Smith"})]
Any tips to figure this out? Thanks
In neo4j 3.x, after you install the APOC plugin on the neo4j server, you can call the apoc.convert.toTree procedure to generate similar results.
For example:
MATCH p=(n:Crew {name:'Neo'})-[:KNOWS*]->(m)
WITH COLLECT(p) AS ps
CALL apoc.convert.toTree(ps) yield value
RETURN value;
... would return a result row that looks like this:
{
"_id": 127,
"_type": "Crew",
"name": "Neo",
"knows": [
{
"_id": 128,
"_type": "Crew",
"name": "Morpheus",
"knows": [
{
"_id": 129,
"_type": "Crew",
"name": "Trinity"
},
{
"_id": 130,
"_type": "Crew:Matrix",
"name": "Cypher",
"knows": [
{
"_id": 131,
"_type": "Matrix",
"name": "Agent Smith"
}
]
}
]
}
]
}
This was such a useful thread on this important topic, I thought I'd add a few thoughts after digging into this a bit further.
First off, using the APOC "toTree" proc has some limits, or better said, dependencies. It really matters how "tree-like" your architecture is. E.g., the LOVES relation is missing in the APOC call above and I understand why – that relationship is hard to include when using "toTree" – that simple addition is a bit like adding an attribute in a hierarchy, but as a relationship. Not bad to do but confounds the simple KNOWS tree. Point being, a good question to ask is “how do I handle such challenges”. This reply is about that.
I do recommend upping ones JSON skills as this will give you much more granular control. Personally, I found my initial exploration somewhat painful. Might be because I'm an XML person :) but once you figure out all the [, {, and ('s, it is really a powerful way to efficiently pull what's best described as a report on your data. And given the JSON is something that can easily become a class, it allows for a nice way to push that back to your app.
I have found perf to also be a challenge with "toTree" vs. just asking for the JSON. I've added below a very simplistic look into what your RETURN could look like. It follows the following BN format. I'd love to see this more maturely created as the possibilities are quite varied, but this was something I'd have found useful thus I’ll post this immature version for now. As they say; “a deeper dive is left up to the readers” 😊
I've obfuscated the values, but this is an actual query on what I’ll term a very poor example of a graph architecture, whose many design “mistakes” cause some significant performance headaches when trying to access a holistic report on the graph. As in this example, the initial report query I inherited took many minutes on a server, and could not run on my laptop - using this strategy, the updated query now runs in about 5 seconds on my rather wimpy laptop on a db of about 200K nodes and .5M relationships. I added the “persons” grouping alias as a reminder that "persons" will be different in each array element, but the parent construct will be repeated over and over again. Where you put that in your hand-grown tree, will matter, but having the ability to do that is powerful.
Bottom line, a mature use of JSON in the RETURN statement, gives you a powerful control over the results in a Cypher query.
RETURN STATEMENT CONTENT:
<cypher_alias>
{.<cypher_alias_attribute>,
...,
<grouping_alias>:
(<cypher_alias>
{.<cypher_alias_attribute,
...
}
)
...
}
MATCH (j:J{uuid:'abcdef'})-[:J_S]->(s:S)<-[:N_S]-(n:N)-[:N_I]->(i:I), (j)-[:J_A]->(a:P)
WHERE i.title IN ['title1', 'title2']
WITH a,j, s, i, collect(n.description) as desc
RETURN j{.title,persons:(a{.email,.name}), s_i_note:
(s{.title, i_notes:(i{.title,desc})})}
if you know how deep your tree is, you can write something like this
MATCH p =(:Crew { name: "Neo" })-[q:KNOWS*0..]-(m)
WITH nodes(p)[0] AS a, nodes(p)[1] AS b, nodes(p)[2] AS c, nodes(p)[3] AS d, nodes(p)[4] AS e
WITH (a{.name}) AS ab, (b{.name}) AS bb, (c{.name}) AS cb, (d{.name}) AS db, (e{.name}) AS eb
WITH ab, bb, cb, db{.*,children:COLLECT(eb)} AS ra
WITH ab, bb, cb{.*,children:COLLECT(ra)} AS rb
WITH ab, bb{.*,children:COLLECT(rb)} AS rc
WITH ab{.*,children:COLLECT(rc)} AS rd
RETURN rd
Line 1 is your query. You save all paths from Neo to m in p.
In line 2 p is split into a, b, c, d and e.
Line 3 takes just the namens of the nodes. If you want all properties you can write (a{.*}) AS ab. This step is optional you can also work with nodes if you want to.
In line 4 you replace db and eb with a map containing all properties of db and the new property children containing all entries of eb for the same db.
Lines 5, 6 and 7 are basically the same. You reduce the result list by grouping.
Finally you return the tree. It looks like this:
{
"name": "Neo",
"children": [
{
"name": "Morpheus",
"children": [
{"name": "Trinity", "children": []},
{"name": "Cypher","children": [
{"name": "Agent Smith","children": []}
]
}
]
}
]
}
Unfortunately this solution only works when you know how deep your tree is and you have to add a row if your tree is one step deeper.
If someone has an idea how to solve this with dynamic tree depth, please comment.
I am building a site with a database of users. I am using arbor.js to build a graph for each user. The graph is a tree-like structure with edges and nodes that looks something like this (I had an image ready to go but apparently don't have enough reputation yet):
vehicle
/ \
/ \
car truck
/
/
sedan
and is represented by the following JSON:
{
"nodes":{
"vehicle":{
"color":"black",
"label":"vehicle"
},
"car":{
"color":"orange",
"label":"car"
},
"truck":{
"color":"red",
"label":"truck"
},
"sedan":{
"color":"red",
"label":"sedan"
}
},
"edges":{
"vehicle":{
"car":{
"weight":5,
"directed":true,
"color":"orange"
},
"truck":{
"weight":5,
"directed":true,
"color":"red"
}
},
"car":{
"sedan":{
"weight":2,
"directed":true,
"color":"orange"
}
}
}
}
Each graph will always have a nodes and edges object with dynamic nodes and edges. Their respective attributes (color, label, weight etc.) will be fixed.
I am trying to figure out how best to model this data for each user. I am using Rails with MongoDB (Mongoid), because I understand that MongoDB can save objects as documents in the database. I'm pretty sure each user will have a graph model which I can define, but beyond that I'm not sure how to handle the nodes and edges.
I'm guessing the solution will involve has_many, embeds_many, or possibly serialize, but I'm unclear on how to use these with a mix of fixed and dynamic data.
Also, it would be nice to retrieve the data exactly the way it looks above so I can easily create the graph when loading it from disk.
Any help would be appreciated!
In case all you need is to perform graph operations only per user. You can follow this model.
{
"nodes": [{"type": "vehicle", "color":"black", "label": "vehicle"},
{"type": "car", "color":"orange", "label": "car"},
{"type":"truck", "color":"red", "label":"truck"},
{"type": "sedan", "color":"red", "label":"sedan"}
],
"edges": {
"vehicle": [
{"type": "car", "weight": 5, "color": "orange"},
{"type": "truck", "weight": 5, "color": "red"}
],
"car": [
{"type": "sedan", "weight": 2, "color": "orange"}
],
"sedan": [],
"truck":: []
}
It is like you are storing a multimap for edges. Also it is self suggestive whether its a bi-directional or not. For individual user's graph to be processed independently, it is a pretty natural model you can go with.
Tell me if it meets your requirement. Also, until you specify what kind of queries you want to perform over your collection, its not possible to suggest a model.
Also if you are starting your project you can explore some graph databases as well like neo4j