<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/SepiaGroup/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/SepiaGroup">@SepiaGroup</a>: 'Enhance the existing REST Unique API to support multiple indexes in one call:  in reference to <a href="https://groups.google.com/forum/?fromgroups#!topic/neo4j/-YryBO8SkkI" rel="nofollow">https://groups.google.com/forum/?fromgroups#!topic/neo4j/-YryBO8SkkI</a></p>
<p dir="auto"><a href="http://localhost:7474/db/data/index/node/unique" rel="nofollow">http://localhost:7474/db/data/index/node/unique</a> {<br>
"indexes": [ {"index":"indexName1", "key": "uid", "value": "Tobias"},<br>
{"index":"indexName2", "key": "email", "value": "<a href="mailto:Tobias@mail.com">Tobias@mail.com</a>"}, ... ]<br>
, "properties": {"name": "Tobias", "sequence"<br>
: 1}}</p>
<p dir="auto">would only be for unique indexes because wouldn't this call only be use for unique indexes regardless of how many index/key/value pairs were passed to it?</p>
<p dir="auto">any other index updates would be called on another REST call as usual and not part of Unique transaction.</p>
<p dir="auto">My thinking is that to ensure uniqueness you need to do the update to multiple indexes in one transaction and that is only possible (as far as i am aware of) over REST if the db does it.</p>
<p dir="auto">Now thinking about the next step - updating:  if you agree with the above then we would also need a way to update the index when required</p>
<p dir="auto"><a href="http://localhost:7474/db/data/index/node/unique" rel="nofollow">http://localhost:7474/db/data/index/node/unique</a> {<br>
"indexes": [ {"index":"indexName1", "key": "uid", "value": "Tobias"},<br>
{"index":"indexName2", "key": "email", "value": "<a href="mailto:Tobias@mail.com">Tobias@mail.com</a>"}, ... ]<br>
, "properties": {"name": "Tobias", "sequence"<br>
: 1}<br>
, "uri":"<a href="http://localhost:7474/db/data/node/116%22%7D" rel="nofollow">http://localhost:7474/db/data/node/116"}</a></p>
<p dir="auto">would be the update call where uri points to the existing node, similar to</p>
<p dir="auto"><a href="http://docs.neo4j.org/chunked/stable/rest-api-unique-indexes.html#rest-api-add-a-node-to-an-index-unless-a-node-already-exists-for-the-given-mapping" rel="nofollow">http://docs.neo4j.org/chunked/stable/rest-api-unique-indexes.html#rest-api-add-a-node-to-an-index-unless-a-node-already-exists-for-the-given-mapping</a></p>
<p dir="auto">all index/key/value pairs would need to be checked against the key/values passed in the properties and if any duplicates are found the update fails for the entire call.  Just like in sql if a key constraint is placed on a column in a table.</p>
<p dir="auto">With this approach there is a very good chance that the index gets out of sync with the node properties (forget to add a index to the update call for example).  maybe you can come up with some magic knowing the internals of the indexing better.</p>
<p dir="auto">just my thoughts.<br>
thanks'</p>
<ul dir="auto">
<li>Neo4j Server version: 4.0.0 (community)</li>
<li>Operating system: Windows server 2012R2</li>
<li>API/Driver: Cypher console web browser (Neo4j Browser version: 4.0.1)</li>
</ul>
<p dir="auto"><strong>NOTE</strong>:  Neo4j Browser version: 4.0.3/Neo4j Server version: 4.0.1 (community) (latest version as of right now) also exhibits the same behavior described below.</p>
<ol dir="auto">
<li>Load data</li>
<li>Run call db.schema.visualization()<br>
The example DB at neo4j console:  <a href="https://console.neo4j.org/r/nt3sgc" rel="nofollow">https://console.neo4j.org/r/nt3sgc</a></li>
</ol>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="create (l1a:Level1 {name:'l1a'})
,(l1b:Level1 {name: 'l1b'})
,(l1c:Level1 {name: 'l1c'})
,(l1d:Level1 {name: 'l1d'})
,(l2a:Level2 {name: 'l2a'})
,(l2b:Level2 {name:'l2b'})
,(l3a:Level3 {name:'l3a'})
,(l1a)-[:OWNED_BY]-&gt;(l2a)
,(l1b)-[:OWNED_BY]-&gt;(l2a)
,(l1c)-[:OWNED_BY]-&gt;(l2b)
,(l1d)-[:OWNED_BY]-&gt;(l2b)
,(l2a)-[:OWNED_BY]-&gt;(l3a)
,(l2b)-[:OWNED_BY]-&gt;(l3a)
;

match (n1:Level1)-[:OWNED_BY]-&gt;(:Level1)
RETURN count(n1) as cnt, 'count_L1_to_L1' as description
UNION
match (n2:Level2)-[:OWNED_BY]-&gt;(:Level2)
RETURN count(n2) as cnt, 'count_L2_to_L2' as description
UNION
match (n3:Level3)-[:OWNED_BY]-&gt;(:Level3)
RETURN count(n3) as cnt, 'count_L3_to_L3' as description
UNION
match (n4:Level1)-[:OWNED_BY]-&gt;(:Level2)
RETURN count(n4) as cnt, 'count_L1_to_L2' as description
UNION 
match (n5:Level2)-[:OWNED_BY]-&gt;(:Level3)
RETURN count(n5) as cnt, 'count_L2_to_L3' as description
;

call db.schema.visualization()"><pre class="notranslate"><code class="notranslate">create (l1a:Level1 {name:'l1a'})
,(l1b:Level1 {name: 'l1b'})
,(l1c:Level1 {name: 'l1c'})
,(l1d:Level1 {name: 'l1d'})
,(l2a:Level2 {name: 'l2a'})
,(l2b:Level2 {name:'l2b'})
,(l3a:Level3 {name:'l3a'})
,(l1a)-[:OWNED_BY]-&gt;(l2a)
,(l1b)-[:OWNED_BY]-&gt;(l2a)
,(l1c)-[:OWNED_BY]-&gt;(l2b)
,(l1d)-[:OWNED_BY]-&gt;(l2b)
,(l2a)-[:OWNED_BY]-&gt;(l3a)
,(l2b)-[:OWNED_BY]-&gt;(l3a)
;

match (n1:Level1)-[:OWNED_BY]-&gt;(:Level1)
RETURN count(n1) as cnt, 'count_L1_to_L1' as description
UNION
match (n2:Level2)-[:OWNED_BY]-&gt;(:Level2)
RETURN count(n2) as cnt, 'count_L2_to_L2' as description
UNION
match (n3:Level3)-[:OWNED_BY]-&gt;(:Level3)
RETURN count(n3) as cnt, 'count_L3_to_L3' as description
UNION
match (n4:Level1)-[:OWNED_BY]-&gt;(:Level2)
RETURN count(n4) as cnt, 'count_L1_to_L2' as description
UNION 
match (n5:Level2)-[:OWNED_BY]-&gt;(:Level3)
RETURN count(n5) as cnt, 'count_L2_to_L3' as description
;

call db.schema.visualization()
</code></pre></div>
<p dir="auto">Here is the database contents as loaded.  It's a simple tree type hierarchy where level 3 is the top node, and level 1 is the most detailed level.  Each level's nodes points upward to a single parent, and there are no links across nodes in the same level.<br>
The match query included above proves that there are relationships shown in the viz that do not exist in the DB.<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/3429424/75811826-beeb1400-5d52-11ea-9f40-7de11c697ef0.jpg"><img src="https://user-images.githubusercontent.com/3429424/75811826-beeb1400-5d52-11ea-9f40-7de11c697ef0.jpg" alt="expected_db_schema_viz_2020-03-03" style="max-width: 100%;"></a></p>
<ul dir="auto">
<li>
<p dir="auto">Expected behavior<br>
Viz should only show relationships between nodes where that type of relationship actually exists in the DB<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/3429424/75812118-46d11e00-5d53-11ea-9f89-0cf93369ffd8.jpg"><img src="https://user-images.githubusercontent.com/3429424/75812118-46d11e00-5d53-11ea-9f89-0cf93369ffd8.jpg" alt="DB_Viz_as_expected" style="max-width: 100%;"></a></p>
</li>
<li>
<p dir="auto">Actual behavior<br>
The viz shows inter-node links between <em>ALL</em> nodes that have the same relationship type instead of just those that actually exist in the DB.<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/3429424/75811839-c4e0f500-5d52-11ea-9d85-4e0da98d6162.jpg"><img src="https://user-images.githubusercontent.com/3429424/75811839-c4e0f500-5d52-11ea-9d85-4e0da98d6162.jpg" alt="DB_Viz_is_wrong" style="max-width: 100%;"></a></p>
</li>
</ul>