Create a Neo4j graph database using details and relationships from Monica.
virtualenv env
source ./env/bin/activate
pip install -r requirements.txt
# TODO: setup secrets file/auth
# Currently looks for secrets.json in the current directory
# {
# "MONICA_TOKEN": "XXXXXXX",
# "NEO4J_PASSWORD": "XXXXXXXX"
# }
- Create an account on Monica or host your own.
- Create a personal access token for your account: https://app.monicahq.com/settings/api
- Add it to
secrets.json
or set the environment variableMONICA_TOKEN
. - Verify access:
python -m monica_client
- Try it out:
python -m monica2neo4j --print
- Create an account on the Neo4j sandbox or host a Neo4j server.
- Create a node and put the password in
secrets.json
or set the environment variableNEO4J_PASSWORD
. - Try it out:
python -m monica2neo4j
$ python -m monica2neo4j --help
usage: monica2neo4j [-h] [--monica MONICA_URL] [--neo4j NEO4J_URL] [--print] [--wipe] [--force]
Copy contact details and relationships from Monica to a Neo4j graph database
optional arguments:
-h, --help show this help message and exit
--monica MONICA_URL, -m MONICA_URL
HTTP(S) address of the desired Monica instance
--neo4j NEO4J_URL, -n NEO4J_URL
Bolt address for the desired Neo4j instance
--print, -p Print the Neo4j queries instead of running them
--wipe, -w Clear the ENTIRE database before populating it from Monica. ALL nodes and relationships will be removed
--force, -f Do not prompt for confirmation of prune or wipe
$ python -m monica2neo4j --print --monica https://app.monicahq.com
...
Once the data is ingested, here are some interesting queries to try out.
Note: If Neo4j isn't displaying a helpful field as the node name, you can switch it:
- After running a query, select the colored node label (i.e.
Contacts
) at the top of the result - Change the
Caption
setting to a different property
// Everything
MATCH (n) RETURN n
// Contacts
MATCH (n:Contact) RETURN n
// Companies
MATCH (n:Company) RETURN n
// Tags
MATCH (n:Tag) RETURN n
// Gender Search
// You can add other properties to the {} list. This will return
// only nodes that have all of the matching properties
MATCH (n:Contact {gender: 'Woman'}) RETURN n
// Contacts at a Company
WITH
'Hotel Winden' AS company
MATCH p=(a:Contact)-[r]-(b:Company)
WHERE b.name = company
RETURN p
// Contacts in a Tag
WITH
'1986' AS tag
MATCH p=(a:Contact)-[r]-(b:Tag)
WHERE b.name = tag
RETURN p
// Shortest Path
// Find the shortest way that two people know each other
WITH
'Hannah' AS first_name_a,
'Helge' AS first_name_b
MATCH p=shortestPath((a:Contact)-[r*..5]-(b:Contact))
WHERE
a.first_name = first_name_a
AND b.first_name = first_name_b
RETURN p
// Shortest Path
// Find the shortest way that two people know each other
// Exclude some types of relationships
WITH
'Hannah' AS first_name_a,
'Helge' AS first_name_b
MATCH p=shortestPath((a:Contact)-[r*..5]-(b:Contact))
WHERE
a.first_name = first_name_a
AND b.first_name = first_name_b
AND none(
x in r WHERE
x.type IN ['tag']
OR x.name IN ['friend']
)
RETURN p
The following queries work/look much better if auto-join is turned off.
- In the Neo4j browser, click the settings icon in the bottom left
- Uncheck
'Connect result nodes'
// Companies & Employees
MATCH p=(a:Company)-[r1]-(b:Contact)
RETURN p
// Family Tree
// A family tree like graph with some generation-skipping or 'redundant'
// relationships excluded so that it flows correctly
MATCH p=(a:Contact)-[r]-(b:Contact)
WHERE (
r.name IN ['spouse']
) OR (
r.type IN ['family']
AND NOT r.name IN ['grandparent', 'grandchild', 'sibling']
)
RETURN p
// Family by last name plus spouses
WITH
'Doppler' AS last_name
MATCH p=((a:Contact)-[r]-(b:Contact))
WHERE
a.last_name = last_name
AND (
b.last_name = last_name
OR r.name IN ['spouse']
)
RETURN p
// Social Circle
// Find all the direct and indirect relationships between two people
// You can increase how many 'hops' this will include by changing the number in 'r*..3'
// You can require that the path contain only certain types/names of relationships in all(...)
// You can exclude certain relationship types/names from the path in none(...)
WITH
'Jonas' AS first_name_a,
'Bartosz' AS first_name_b
MATCH p=((a:Contact)-[r*..3]-(b:Contact))
WHERE
a.first_name = first_name_a
AND b.first_name = first_name_b
AND all(
rel in r WHERE
rel.type IN ['friend']
AND rel.name IN ['friend']
)
AND none(
rel in r WHERE
rel.type IN []
AND rel.name IN []
)
RETURN p