Inherit properties from a node with relationship to another node to its child in neo4j - graph

Inherit properties from all the parents.
Consider I have a graph with below format. I want the properties of a node (which will be in account node, if it has a relation) to be inherited by its child node. Assume Parent and child node relationship is maintained by [r:CHILD] and account information by [r2:ACCOUNT]. If node has more than one parent, it needs to inherit from all its parent with the first account :
(a0:ACCOUNT)<-[:HAS_ACCOUNT]-Morpheus
\
(a1:ACCOUNT)<-[:HAS_ACCOUNT]-Neo
\
alpha
\
gamma beta - [:HAS_ACCOUNT]->(a2:ACCOUNT)
\ /
A
/ \
(a3:ACCOUNT)<-[:HAS_ACCOUNT]-B C
/ \ / \
D E F G
I want to extract the data from the above graph something like this:
Problem: Given a node, get all its children and also its account (if it has account , e.g: see node B) or its inherited account information. AccountID is part of account node
Consider input is node A
OUTPUT:
|Node | CurrentNode| Account |Inherited_Account|
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | A | - | a1.accountID ,|
| | | | a2.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | B | a3.accountID | - |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | D | | a3.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | E | | a3.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | C | | a1.accountID ,|
| | | | a2.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | F | | a1.accountID ,|
| | | | a2.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | G | | a1.accountID ,|
| | | | a2.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
This was my cypher to retrive that I came up with, gets me all the accounts of all the parents. It doesnt work sometimes
MATCH (node:Person{personID:"A"})
MATCH (account:ACCOUNT)
MATCH p =(parent:Person)-[:CHILD*1..]->(node)
where (parent)-[:HAS_ACCOUNT]->(account)
UNWIND RELATIONSHIPS(p) AS rel
WITH p, account, COUNT(DISTINCT rel) AS nRoutes
RETURN account,p, nRoutes
ORDER BY nRoutes

This is a tricky one.
A pure Cypher solution exists, but it's a complicated query and requires some potentially heavy filtering to weed out paths to account-holding nodes that are beyond closer account-holding nodes along the same path.
However, I've found a better alternate using Cypher and APOC's path expander, plus some pre-processing of adding a label to nodes that are account holders.
APOC's path expander has a means of expanding while respecting a label filter, and there is a means to define a label which should prune any further traversal, but be included as a solution. We'll use this to limit our expansion when getting account-holding ancestors for nodes.
Here's a creation query to recreate the graph in your example (though I'm labeling non-ACCOUNT nodes as :Node):
// create inherited account graph
create (morpheus:Node{name:'Morpheus'})
create (neo:Node{name:'Neo'})
create (alpha:Node{name:'alpha'})
create (gamma:Node{name:'gamma'})
create (beta:Node{name:'beta'})
create (A:Node{name:'A'})
create (B:Node{name:'B'})
create (C:Node{name:'C'})
create (D:Node{name:'D'})
create (E:Node{name:'E'})
create (F:Node{name:'F'})
create (G:Node{name:'G'})
create (morpheus)-[:CHILD]->(neo)
create (neo)-[:CHILD]->(alpha)
create (alpha)-[:CHILD]->(gamma)
create (gamma)-[:CHILD]->(A)
create (beta)-[:CHILD]->(A)
create (A)-[:CHILD]->(B)
create (A)-[:CHILD]->(C)
create (B)-[:CHILD]->(D)
create (B)-[:CHILD]->(E)
create (C)-[:CHILD]->(F)
create (C)-[:CHILD]->(G)
create (morpheus)-[:HAS_ACCOUNT]->(a0:ACCOUNT{name:'a0'})
create (neo)-[:HAS_ACCOUNT]->(a1:ACCOUNT{name:'a1'})
create (beta)-[:HAS_ACCOUNT]->(a2:ACCOUNT{name:'a2'})
create (B)-[:HAS_ACCOUNT]->(a3:ACCOUNT{name:'a3'})
Next, we label account-holding nodes.
MATCH (acc:ACCOUNT)
WITH acc
MATCH (acc)<-[:HAS_ACCOUNT]-(holder)
SET holder:ACCOUNT_HOLDER
Once that's in place, we can use the following query to get your desired output:
// parameterize this in your own query
with 'A' as nodeName
match (node:Node{name:nodeName})-[r:CHILD*0..]->(currentNode)
with node, currentNode, size(r) as distance
optional match (currentNode)-[:HAS_ACCOUNT]->(acc)
with node, currentNode, distance, collect(acc) as accounts
// we now have all child nodes of the given node and their accounts, if they exist.
// this expands up from each currentNode,
// stopping each expansion at the closest ACCOUNT_HOLDER node
call apoc.path.expand(currentNode, '<CHILD', '/ACCOUNT_HOLDER', -1, -1)
yield path
with node, currentNode, distance, accounts, last(nodes(path)) as holder
// get the account for each holder,
// but only if the current doesn't have its own accounts
optional match (holder)-[:HAS_ACCOUNT]->(acc)
where size(accounts) = 0
with node, currentNode, accounts, collect(acc) as inherited, distance
order by distance asc
return node, currentNode, accounts, inherited
However, note that even with this approach, the query will not build up and reuse solutions (for example, once we've found the account-holding ancestors for node A, that solution is not referenced or reused when we have to get the account-holding ancestors for nodes, C, F, or G). You may want to consider a custom procedure to perform this complicated matching operation in code rather than Cypher for maximum efficiency.

Related

How can I define local dependencies between roles in a collection in ansible?

I have a question about dependencies between roles in a collection.
In general, I am concerned if it is possible to define dependencies between roles in a collection - local dependencies like a relative path.
I would like to implement scenarios:
roleB depends on roleA
default scenario of roleC should use roleA in prepare.yml to set up the environment
or
default scenario of roleC should use roleA in converge.yml
I would like to get these dependencies as local dependencies.
For case 2, I tried to use the requriments.yml file
with the appropriate entry in molecule.yml
---
dependency:
name: galaxy
driver:
name: docker
platforms:
.. ...
provisioner:
name: ansible
# env:
# ANSIBLE_ROLES_PATH: "../../roles"
playbooks:
prepare: prepare.yml
config_options:
defaults:
remote_user: ansible
dependency:
name: galaxy
options:
ignore-certs: True
ignore-errors: True
requirements-file: requirements.yml
verifier:
name: ansible
But unfortunately I can't solve the error:
ERROR [1m[0;34mUsing /etc/ansible/ansible.cfg as config file[1m[0m
Starting galaxy role install process
- downloading role from file://../../tool-box
[1m[0;31m [ERROR]: failed to download the file: <urlopen error [Errno 2] No such file or[1m[0m
[1m[0;31mdirectory: '/../tool-box'>[1m[0m
[1m[1;35m[WARNING]: - tool-box was NOT installed successfully.[1m[0m
[1m[0;31mERROR! - you can use --ignore-errors to skip failed roles and finish processing the list.[1m[0m
Structure of collection with roles:
mynamespace
|
|-- mycollection
|
| --roles
|
| -- roleA --
| |--molecule
| |
| |--default
|
| -- roleB --
| |--molecule
| |
| |--default
|
| -- roleC --
| |--molecule
| |
| |--default
Thank you.
Update:
See request issue in ansible/galaxy:
https://github.com/ansible/galaxy/issues/2719
I added this because I don't think there is such functionality.

Firebase security rules: Get a document with a space in the documentID

I am writing firebase security rules, and I am attempting to get a document that may have a space in its documentID.
I have the following snippet which works well when the document does not have a space
function isAdminOfCompany(companyName) {
let company = get(/databases/$(database)/documents/Companies/$(companyName));
return company.data.authorizedUsers[request.auth.uid].access == "ADMIN;
}
Under the collection, "Companies", I have a document called "Test" and another called "Test Company" - Trying to get the document corresponding to "Test" works just fine, but "Test Company" does not seem to work, as the company variable (first line into the function) is equal to null as per the firebase security rules "playground".
My thought is that there is something to do with URL encoding, but replacing the space in a documentID to "%20" or a "+" does not change the result. Perhaps spaces are illegal characters for documentIDs (https://cloud.google.com/firestore/docs/best-practices lists a few best practices)
Any help would be appreciated!
EDIT: As per a few comments, I Will add some additional images/explanations below.
Here is the structure of my database
And here is what fields are present in the user documents
In short, the following snippet reproduces the problem (I am not actually using this, but it demonstrates the issue the same way)
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /Users/{user} {
allow update: if findPermission(resource.data.company) == "MASTER"
}
function findPermission(companyName) {
let c = get(path("/databases/" + database + "/documents/Companies/" + companyName));
return c.data.authorizedUsers[request.auth.uid].access;
}
}
}
When I try to update a user called test#email.com (which belongs to company "Test"), the operation is permitted, and everything works exactly as expected.
The issue arises when a user, called test2#email.com, who belongs to company "Test Company" comes along and makes the same request (with authorization email/uid updated in playground, to match what is actually found in the company structure), the request fails. The request fails, since the get() call (line 1 of the function) cannot find the Company document corresponding to "Test Company" - indicated by the variable "c" being null in the screenshot (see below) - IT IS NOT NULL WHEN LOOKING FOR "Test"
Below is a screenshot of the error message, as well as some of the relevant variables when the error occurs
Check to see what type of space just in case it is another non-printable character. You could convert it to Unicode, and check what it might be. However, it is considered bad practice to use spaces in naming variables and data structures. There are so many different types to consider.
| Unicode | HTML | Description | Example |
|---------|--------|--------------------|---------|
| U+0020 | &#32 | Space | [ ] |
| U+00A0 | &#160 | No-Break Space | [ ] |
| U+2000 | &#8192 | En Quad | [ ] |
| U+2001 | &#8193 | Em Quad | [ ] |
| U+2002 | &#8194 | En Space | [ ] |
| U+2003 | &#8195 | Em Space | [ ] |
| U+2004 | &#8196 | Three-Per-Em Space | [ ] |
| U+2005 | &#8197 | Four-Per-Em Space | [ ] |
| U+2006 | &#8198 | Six-Per-Em Space | [ ] |
| U+2007 | &#8199 | Figure Space | [ ] |
| U+2008 | &#8200 | Punctuation Space | [ ] |
| U+2009 | &#8201 | Thin Space | [ ] |
| U+200A | &#8202 | Hair Space | [ ] |

how to delete an account after a post request

On my method accountRepo.deleteAll()
return error:
2020-06-04 15:37:05.069 ERROR 78168 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : ОШИБКА: UPDATE or DELETE in table "account" violates foreign key constraint "fk8k31xl4ld2m810mxfkqp2xg8g" from table "tokens"
Details: on a key (account_id)=(2) there are still links in the table "tokens".
2020-06-04 15:37:05.071 INFO 78168 --- [ main] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
What could be the problem? This happens when creating a post-request with the registration of a user who will fall into accountRepo
My test and post-request:
#Test
#Throws(Exception::class)
fun shouldRegistrationExpected201() {
val headers = HttpHeaders()
headers.contentType = MediaType.APPLICATION_JSON
val request = HttpEntity<String>("{\"username\": \"holker228\", \"password\": \"123456QQwerty&&\",\"email\":\"test2#mail.ru\",\"is_collective\": \"false\" }", headers)
val responseEntity = restTemplate.postForEntity("http://localhost:$port/api/user/registration", request, String::class.java)
assertEquals(responseEntity.statusCode, HttpStatus.CREATED)
}
The issue seems to be in constrains configured in your database. BTW, which one do you use? In your particular case the constraint disallows DELETE (UPDATE?) operation as the row you're trying to delete seems to have dependent rows in another table.
E.g, imagine you have a table "users" and "comments":
users:
-------------
| ID | Name |
-------------
| 1 | Max |
-------------
| 2 | Vova |
-------------
| 3 | Vlad |
-------------
comments:
---------------------------------
| ID | User ID | Text |
---------------------------------
| 1 | 1 | Max was here! |
---------------------------------
| 2 | 1 | Vova + Vlad = ❤️ |
---------------------------------
| 3 | 2 | Don't listen to Max! |
---------------------------------
Here, if the constrains are configured, you cannot delete Max (1) or Vova (2) from "users" as they have comments. Imagine, you're rendering an HTML page and you need to render a comment's author's name? What would you do, if the author is deleted? (well, you can use "Anonymous", but let's not think about it). You cannot either change Max's or Vova's IDs for the same reason. So that's what constraints are for: they prevent such unconsistencies.
Ways to deal with this situation:
Update the related entities in the same transaction.
Use CASCADE for DELETEs. Take a look at this answer, for example
Freeze the IDs and do not change them.

How to use variable values in salt formula?

Consider my SLS file,
state1:
cmd.run:
- order: 1
- name: |
USER_NAME='username'
USERPWD='password'
DB_NAME='test'
USER_TOBE_CREATED='new_user'
PASSWORD='newpass'
mysql_user.present:
- order: 2
- host: localhost
- username: USER_TOBE_CREATED
- password: PASSWORD
- connection_user: USER_NAME
- connection_pass: USERPWD
- connection_charset: utf8
- saltenv:
- LC_ALL: "en_US.utf8"
mysql_grants.present:
- order: 3
- grant: all privileges
- database: DB_NAME.*
- user: USER_TOBE_CREATED
In the states mysql_user.present and mysql_grants.present I am using the variables USER_TOBE_CREATED,USER_NAME,USERPWD etc whose values are assigned in state cmd.run. How will I make these two following states to use the actual values of those variables?. Here it's taking variable name itself as the value.
You may want to declare the variables in the state file itself, i.e.:
{% set user_name = "name" %}
and:
state1:
cmd.run:
- order: 1
- name: |
USER_NAME='{{ user_name }}'
You can re-use the variable as many times as you want inside the state file.
Let me know if this helped.

BNF Parse Tree Inquiry

I am currently enrolled in a computer architecture class and I'm trying to do one of the homework assignments.
The assignment is on BNF and even after having the lecture, reading the slides, and looking online, I'm still stumped.
Here is my grammar:
<expr>-><expr> + <term> |
<expr> - <term> |
<term>
<term>-><term> * <factor> |
<term> / <factor> |
<factor>
<factor>->(<expr>)|<id>
<id>->A|B|C|D
What would the parse tree look like for A + (C - D) / B?
I just need a little guidance and I will be able to do this problem for myself. My teacher does not explain very well so I was hoping for explanation in laymans terms of how to go about this?
Though it is not stated, I assume that we are trying to interpret the string A + (C - D) / B as an <expr> (as no other parse works).
<expr> is a nonterminal symbol, i.e. it does not occur literally the final string. Rather, the first rule (<expr> -> <expr> + <term> | <expr> - <term> | <term>) tells us what symbols to expect in a string that is an <expr>. It states that an <expr> can be made from one of the following options:
<expr> + <term>, i.e. an <expr> followed by + followed by a <term>, or
<expr> - <term>, (interpreted similarly), or
<term>
Without getting into the details of how a parser would mechanically make the decision, we have to choose one of these options to proceed building a parse tree. I will choose the first option (<expr> + <term>), which assumes that the first <expr> will represent the A in the message, the + is literally the +, and the <term> is the remaining (C - D) / B. Thus the beginning of our parse tree looks like:
<expr>
/ | \
/ | \
<expr> + <term>
This is not yet a complete parse, as it is not immediately clear from the rules that an <expr> can give the result A. Likewise (C - D) / B is not an immediate option for <term>. We can answer the first objection by seeing that:
<expr> can be <term> (by the third option of the rule for <expr>)
<term> in turn can be <factor> (by the third option of the rule for <term>)
<factor> can be <id> (by the second option of the rule for <factor>), and finally
<id> can be A (by the first option of the rule for <id>)
This line of reasoning fills in the parse tree as follows:
<expr>
/ | \
/ | \
<expr> | <term>
| |
<term> |
| |
<factor>|
| |
<id> |
| |
A +
I hope that this gives you an idea of the process and the meaning of the rules, so that you can show further how <term> can give (C - D) / B and thus fill in the rest of the tree.

Resources