{ "cells": [ { "cell_type": "markdown", "id": "22d93371-d72a-498a-b25e-affb11659f0d", "metadata": {}, "source": [ "## NeoAccess library - Tutorial 2 : identical to tutorial 1, but with the DEBUG option turned on.\n", "### As a result, the Cypher queries and the data binding managed by `NeoAccess` will become visible.\n", "\n", "### NOTE: only meant for people who are knowledgeable about Cypher, and want an under-the-hood look at the `NeoAccess` library! General users should use the other tutorials.\n", "\n", "#### (`debug` mode **ON**)\n", "\n", "#### [Overview and Intro article](https://julianspolymathexplorations.blogspot.com/2023/06/neo4j-python-neoaccess-library.html) to accompany these tutorials\n", "\n", "#### CAUTION: running this tutorial runs a risk of clearing out your database; best run on a test database!" ] }, { "cell_type": "code", "execution_count": 1, "id": "e00686a6-c019-414e-92be-a44d32cfe138", "metadata": { "tags": [] }, "outputs": [], "source": [ "import os\n", "import sys\n", "import getpass\n", "\n", "from brainannex import GraphAccess\n", "# In case of problems, try a sys.path.append(directory) , where directory is your project's root directory" ] }, { "cell_type": "markdown", "id": "be1fb174-5bb9-4dee-a920-0ac5dcfb74a5", "metadata": {}, "source": [ "# Connect to the database\n", "#### You can use a free local install of the Neo4j database, or a remote one on a virtual machine under your control, or a hosted solution, or simply the FREE \"Sandbox\" : [instructions here](https://julianspolymathexplorations.blogspot.com/2023/03/neo4j-sandbox-tutorial-cypher.html)" ] }, { "cell_type": "code", "execution_count": 2, "id": "d755c335-7691-4712-8ddd-a84157f2c45c", "metadata": { "tags": [] }, "outputs": [], "source": [ "# Save your credentials here - or use the prompts given by the next cell\n", "host = \"bolt://localhost\" # EXAMPLES: bolt://123.456.789.012 OR bolt://localhost\n", " # (CAUTION: do NOT include the port number!)\n", "password = \"\"" ] }, { "cell_type": "code", "execution_count": 3, "id": "7247f139-9f06-41d1-98e8-410ff7c9f177", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "~~~~~~~~~ Initializing Intergraph object ~~~~~~~~~\n", "Attempting to connect to Neo4j host 'bolt://localhost', with username 'neo4j'...\n", "\n", "In query(). Query:\n", " MATCH (n) RETURN n LIMIT 1\n", "\n", " single_row: False , single_cell: `` , single_column : ``\n", "Connection to host 'bolt://localhost' established. *** IN DEBUG MODE ***\n" ] } ], "source": [ "db = GraphAccess(host=host,\n", " credentials=(\"neo4j\", password), debug=True) # Notice the debug option being ON" ] }, { "cell_type": "code", "execution_count": 4, "id": "c96ece03-2b07-4a4d-ad6e-e41ccbf67251", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Version of the Neo4j driver: 4.4.13\n" ] } ], "source": [ "print(\"Version of the Neo4j driver: \", db.version())" ] }, { "cell_type": "code", "execution_count": null, "id": "4848c8c3-dd2e-4130-97d5-f8772b7d57e6", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "4ca98da0-f267-4efa-8302-624efbd1a744", "metadata": {}, "source": [ "# Examples of basic `GraphAccess` library operations" ] }, { "cell_type": "code", "execution_count": 5, "id": "e0533783-5b17-48da-aea3-ab9b8a658072", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query(). Query:\n", " MATCH (n) DETACH DELETE(n)\n", "\n", " single_row: False , single_cell: `` , single_column : ``\n" ] } ], "source": [ "# CLEAR OUT THE DATABASE\n", "#db.empty_dbase() # UNCOMMENT IF DESIRED ***************** WARNING: USE WITH CAUTION!!! ************************" ] }, { "cell_type": "code", "execution_count": 6, "id": "9b1f3651-f613-4966-b1ac-f2eddfbb2e79", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query_extended(). Query:\n", " CREATE (n :`Car` {`color`: $par_1, `make`: $par_2}) RETURN n\n", "Data binding:\n", " {'par_1': 'white', 'par_2': 'Toyota'}\n", "\n", " flatten: True , fields_to_exclude: None\n", "\n", "In query_extended(). Query:\n", " CREATE (n :`Person` {`name`: $par_1}) RETURN n\n", "Data binding:\n", " {'par_1': 'Julian'}\n", "\n", " flatten: True , fields_to_exclude: None\n" ] } ], "source": [ "# Create a \"Car\" node and a \"Person\" node\n", "\n", "neo_car = db.create_node(\"Car\", {'color': 'white', 'make': 'Toyota'}) # create_node returns the internal database ID of the new node\n", "\n", "neo_person = db.create_node(\"Person\", {'name': 'Julian'})" ] }, { "cell_type": "code", "execution_count": 7, "id": "5063cec5-e693-4002-aa84-c5c71240039d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In update_query(). Query:\n", " \n", " MATCH (from), (to)\n", " WHERE (id(from) = 3470 AND id(to) = 3471)\n", " MERGE (from) -[:`OWNED_BY`]-> (to) \n", " \n", "\n", " In update_query(). Attributes of ResultSummary object:\n", " metadata -> {'query': '\\n MATCH (from), (to)\\n WHERE (id(from) = 3470 AND id(to) = 3471)\\n MERGE (from) -[:`OWNED_BY`]-> (to) \\n ', 'parameters': {}, 'server': , 't_first': 15, 'fields': [], 'bookmark': 'FB:kcwQvb2+baJ+TrKHXmXfUdIVwsoAB6BikA==', 'stats': {'contains-updates': True, 'relationships-created': 1}, 'type': 'w', 't_last': 0, 'db': 'neo4j', 'notifications': [{'severity': 'WARNING', 'description': 'If a part of a query contains multiple disconnected patterns, this will build a cartesian product between all those parts. This may produce a large amount of data and slow down query processing. While occasionally intended, it may often be possible to reformulate the query that avoids the use of this cross product, perhaps by adding a relationship between the different parts or by using OPTIONAL MATCH (identifier is: (to))', 'code': 'Neo.ClientNotification.Statement.CartesianProductWarning', 'position': {'column': 13, 'offset': 13, 'line': 2}, 'title': 'This query builds a cartesian product between disconnected patterns.'}]}\n", " server -> \n", " database -> neo4j\n", " query -> \n", " MATCH (from), (to)\n", " WHERE (id(from) = 3470 AND id(to) = 3471)\n", " MERGE (from) -[:`OWNED_BY`]-> (to) \n", " \n", " parameters -> {}\n", " query_type -> w\n", " plan -> None\n", " profile -> None\n", " notifications -> [{'severity': 'WARNING', 'description': 'If a part of a query contains multiple disconnected patterns, this will build a cartesian product between all those parts. This may produce a large amount of data and slow down query processing. While occasionally intended, it may often be possible to reformulate the query that avoids the use of this cross product, perhaps by adding a relationship between the different parts or by using OPTIONAL MATCH (identifier is: (to))', 'code': 'Neo.ClientNotification.Statement.CartesianProductWarning', 'position': {'column': 13, 'offset': 13, 'line': 2}, 'title': 'This query builds a cartesian product between disconnected patterns.'}]\n", " counters -> {'_contains_updates': True, 'relationships_created': 1}\n", " result_available_after -> 15\n", " result_consumed_after -> 0\n" ] }, { "data": { "text/plain": [ "1" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Link the \"Car\" node to the \"Person\" node (using internal database ID's to refer to existing nodes)\n", "number_added = db.add_links(match_from=neo_car, match_to=neo_person, rel_name=\"OWNED_BY\") \n", "\n", "number_added" ] }, { "cell_type": "markdown", "id": "07da197f-2b2a-4c9b-979f-b8d785ef2484", "metadata": {}, "source": [ "![Two nodes and a link](https://raw.githubusercontent.com/BrainAnnex/brain-annex/main/docs/tutorials_1.png)" ] }, { "cell_type": "code", "execution_count": 8, "id": "151b9ffc-2cdc-4f49-837f-001cf1dab1d2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query_extended(). Query:\n", " MATCH (n) WHERE (id(n) = 3470) RETURN n\n", "\n", " flatten: True , fields_to_exclude: ['internal_id', '_node_labels']\n" ] }, { "data": { "text/plain": [ "[{'color': 'white', 'make': 'Toyota'}]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Retrieve the car node (in the most straightforward way, using an internal database ID)\n", "db.get_nodes(neo_car)" ] }, { "cell_type": "code", "execution_count": 9, "id": "b33d4866-3f90-402f-94da-5b9cdfb67666", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query_extended(). Query:\n", " MATCH (n) WHERE (id(n) = 3470) RETURN n\n", "\n", " flatten: True , fields_to_exclude: ['internal_id', '_node_labels']\n" ] }, { "data": { "text/plain": [ "'white'" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Retrieve a single property of the car node (to be used when only 1 node is present)\n", "db.get_nodes(neo_car, single_cell=\"color\")" ] }, { "cell_type": "code", "execution_count": 10, "id": "cf9dec5d-2376-4a63-a1ab-24d5fbfc1dc2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query(). Query:\n", " MATCH (n) - [:OWNED_BY] -> (neighbor )WHERE (id(n) = 3470) RETURN count(neighbor) AS link_count\n", "\n", " single_row: False , single_cell: `link_count` , single_column : ``\n" ] }, { "data": { "text/plain": [ "1" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# How many owners does the car have?\n", "db.count_links(neo_car, rel_name=\"OWNED_BY\", rel_dir=\"OUT\") " ] }, { "cell_type": "code", "execution_count": 11, "id": "df19cdc1-992b-471b-8fa2-ada0fb4c226d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query(). Query:\n", " MATCH (n) - [:OWNED_BY] -> (neighbor )WHERE (id(n) = 3470) RETURN neighbor LIMIT 100\n", "\n", " single_row: False , single_cell: `` , single_column : ``\n" ] }, { "data": { "text/plain": [ "[{'name': 'Julian'}]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Look up information about the car owner(s)\n", "db.follow_links(neo_car, rel_name=\"OWNED_BY\", rel_dir=\"OUT\") " ] }, { "cell_type": "code", "execution_count": null, "id": "4421d8a7-7352-4261-9f55-1acf8ec612a0", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "4f7bc9b8-3bdb-4e05-a70c-1c73b80350ad", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "1773abbf-a595-45eb-979a-0e41ed21b1de", "metadata": {}, "source": [ "#### Let's pretend we didn't save the internal database ID's of our 2 nodes; let's specify those nodes, for the purpose of *LATER* retrieving them from the database" ] }, { "cell_type": "code", "execution_count": 12, "id": "a07e719a-fa52-4752-b29c-98009d8f3709", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Lets provide a way to later look up the \"Car\" node, using the match() method.\n", "# IMPORTANT: NO DATABASE OPERATION IS ACTUALLY PERFORMED HERE! We're just saving up all the specs \n", "# (to indentify a node, OR GROUP OF NODES) into an object of class \"NodeSpecs\"\n", "\n", "car_match = db.match(labels=\"Car\", properties={'color': 'white', 'make': 'Toyota'})\n", "\n", "car_match" ] }, { "cell_type": "code", "execution_count": 13, "id": "880855dd-f5bb-4cd2-bb03-bb62d32cfd34", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Object properties:\n", " internal_id: None\n", " labels: Car\n", " key_name: None\n", " key_value: None\n", " properties: {'color': 'white', 'make': 'Toyota'}\n", " clause: \n", " clause_binding: {}\n", " dummy_node_name: n\n", " \n", " node: (n :`Car` {`color`: $n_par_1, `make`: $n_par_2})\n", " where: \n", " \n", " data_binding: {'n_par_1': 'white', 'n_par_2': 'Toyota'}\n", " cypher: MATCH (n :`Car` {`color`: $n_par_1, `make`: $n_par_2})\n", " \n" ] } ], "source": [ "print(car_match) # Let's look at the specs we saved up; they will be used LATER in actual database operations" ] }, { "cell_type": "code", "execution_count": 14, "id": "4c847fcc-ec87-4b53-b430-06419eb3c559", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Object properties:\n", " internal_id: None\n", " labels: Car\n", " key_name: None\n", " key_value: None\n", " properties: {}\n", " clause: n.color = 'white' AND n.make = 'Toyota'\n", " clause_binding: {}\n", " dummy_node_name: n\n", " \n", " node: (n :`Car` )\n", " where: n.color = 'white' AND n.make = 'Toyota'\n", " \n", " data_binding: {}\n", " cypher: MATCH (n :`Car` ) WHERE (n.color = 'white' AND n.make = 'Toyota')\n", " \n" ] } ], "source": [ "# A lot of parameters can be passed to match(). Some examples of alternative ways to specify the same node as above:\n", "\n", "car_match_alt = db.match(labels=\"Car\", clause=\"n.color = 'white' AND n.make = 'Toyota'\", dummy_node_name=\"n\")\n", "\n", "print(car_match_alt)" ] }, { "cell_type": "code", "execution_count": null, "id": "bb5f1a05-c390-424c-a555-f6c99fdb4832", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 15, "id": "b93024b0-38e4-4b5e-8e3c-bff5803c939f", "metadata": {}, "outputs": [], "source": [ "# Various ways to specify our Person node (again, NO DATABASE OPERATION IS ACTUALLY PERFORMED HERE!)\n", "\n", "person_match = db.match(labels=\"Person\", properties={'name': 'Julian'})\n", "person_match_alt_1 = db.match(labels=\"Person\", clause=\"n.name = 'Julian'\", dummy_node_name=\"n\")\n", "person_match_alt_2 = db.match(labels=\"Person\", key_name='name', key_value='Julian')" ] }, { "cell_type": "markdown", "id": "eb027c7b-fa86-49fc-8ab8-2500040c3ddd", "metadata": {}, "source": [ "#### Armed with the \"NodeSpecs\" objects, we can do all sort of operations - passing those objects (serving as \"handles\") in lieu of the internal database ID's that we lack (and which would require extra database operations to retrieve)\n", "Note: NO EXTRA DATABASE OPERATIONS ARE WASTED ON LOCATING THE NODES! Efficient, 1-step, database queries are created and executed at the very LAST stage; for example to create the following link" ] }, { "cell_type": "code", "execution_count": 16, "id": "c4dda08b-84f0-40ab-affb-af604fa41d10", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In update_query(). Query:\n", " \n", " MATCH (from :`Person` {`name`: $from_par_1}), (to :`Car` {`color`: $to_par_1, `make`: $to_par_2})\n", " \n", " MERGE (from) -[:`OWNS`]-> (to) \n", " \n", "Data binding:\n", " {'from_par_1': 'Julian', 'to_par_1': 'white', 'to_par_2': 'Toyota'}\n", "\n", " In update_query(). Attributes of ResultSummary object:\n", " metadata -> {'query': '\\n MATCH (from :`Person` {`name`: $from_par_1}), (to :`Car` {`color`: $to_par_1, `make`: $to_par_2})\\n \\n MERGE (from) -[:`OWNS`]-> (to) \\n ', 'parameters': {'from_par_1': 'Julian', 'to_par_1': 'white', 'to_par_2': 'Toyota'}, 'server': , 't_first': 32, 'fields': [], 'bookmark': 'FB:kcwQvb2+baJ+TrKHXmXfUdIVwsoAB6BjkA==', 'stats': {'contains-updates': True, 'relationships-created': 1}, 'type': 'w', 't_last': 0, 'db': 'neo4j', 'notifications': [{'severity': 'WARNING', 'description': 'If a part of a query contains multiple disconnected patterns, this will build a cartesian product between all those parts. This may produce a large amount of data and slow down query processing. While occasionally intended, it may often be possible to reformulate the query that avoids the use of this cross product, perhaps by adding a relationship between the different parts or by using OPTIONAL MATCH (identifier is: (to))', 'code': 'Neo.ClientNotification.Statement.CartesianProductWarning', 'position': {'column': 13, 'offset': 13, 'line': 2}, 'title': 'This query builds a cartesian product between disconnected patterns.'}]}\n", " server -> \n", " database -> neo4j\n", " query -> \n", " MATCH (from :`Person` {`name`: $from_par_1}), (to :`Car` {`color`: $to_par_1, `make`: $to_par_2})\n", " \n", " MERGE (from) -[:`OWNS`]-> (to) \n", " \n", " parameters -> {'from_par_1': 'Julian', 'to_par_1': 'white', 'to_par_2': 'Toyota'}\n", " query_type -> w\n", " plan -> None\n", " profile -> None\n", " notifications -> [{'severity': 'WARNING', 'description': 'If a part of a query contains multiple disconnected patterns, this will build a cartesian product between all those parts. This may produce a large amount of data and slow down query processing. While occasionally intended, it may often be possible to reformulate the query that avoids the use of this cross product, perhaps by adding a relationship between the different parts or by using OPTIONAL MATCH (identifier is: (to))', 'code': 'Neo.ClientNotification.Statement.CartesianProductWarning', 'position': {'column': 13, 'offset': 13, 'line': 2}, 'title': 'This query builds a cartesian product between disconnected patterns.'}]\n", " counters -> {'_contains_updates': True, 'relationships_created': 1}\n", " result_available_after -> 32\n", " result_consumed_after -> 0\n" ] }, { "data": { "text/plain": [ "1" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Link the \"Person\" node to the \"Car\" node (a reverse link of the one we created before)\n", "# HERE'S WHERE THE (SINGLE) DATABASE OPERATION ACTUALLY GETS PERFORMED\n", "number_added = db.add_links(match_from=person_match, match_to=car_match, rel_name=\"OWNS\") \n", "\n", "number_added" ] }, { "cell_type": "markdown", "id": "bdbb2c0e-4066-46b4-a079-942fc93ad6c7", "metadata": {}, "source": [ "![Two nodes and a link](https://raw.githubusercontent.com/BrainAnnex/brain-annex/main/docs/tutorials_1.png)" ] }, { "cell_type": "code", "execution_count": null, "id": "5a512584-44bd-49b4-aa19-4e08089d5561", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "4e52ba28-7a5c-4c54-b562-3c9634b707c8", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "f25143d8-3bcd-4646-ab25-d1fe8ece4feb", "metadata": {}, "source": [ "#### Some verifications" ] }, { "cell_type": "markdown", "id": "e59946fa-b39a-4aa3-8f36-4319c3e01d8c", "metadata": {}, "source": [ "The \"Car\" node can be found and extracted (performing a DATABASE OPERATION), using EITHER its Internal Database ID (which we had saved at the very beginning, though we we were acting like we didn't) OR any of the alternative ways we created to specify it" ] }, { "cell_type": "code", "execution_count": 17, "id": "47426b69-2b3d-4b6e-91d3-4dc673fc5a24", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query_extended(). Query:\n", " MATCH (n) WHERE (id(n) = 3470) RETURN n\n", "\n", " flatten: True , fields_to_exclude: ['internal_id', '_node_labels']\n" ] }, { "data": { "text/plain": [ "[{'color': 'white', 'make': 'Toyota'}]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.get_nodes(neo_car) # Fetch by the internal database ID" ] }, { "cell_type": "code", "execution_count": 18, "id": "2a4ab85a-63a4-4a1d-85c6-6637e1ec766e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query_extended(). Query:\n", " MATCH (n :`Car` {`color`: $n_par_1, `make`: $n_par_2}) RETURN n\n", "Data binding:\n", " {'n_par_1': 'white', 'n_par_2': 'Toyota'}\n", "\n", " flatten: True , fields_to_exclude: ['internal_id', '_node_labels']\n" ] }, { "data": { "text/plain": [ "[{'color': 'white', 'make': 'Toyota'}]" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.get_nodes(car_match) # Fetch by \"NodeSpecs\" object returned by the match() method" ] }, { "cell_type": "code", "execution_count": 19, "id": "612e4b7a-1feb-49c9-aaf0-feecf8195e9a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query_extended(). Query:\n", " MATCH (n :`Car` ) WHERE (n.color = 'white' AND n.make = 'Toyota') RETURN n\n", "\n", " flatten: True , fields_to_exclude: ['internal_id', '_node_labels']\n" ] }, { "data": { "text/plain": [ "[{'color': 'white', 'make': 'Toyota'}]" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.get_nodes(car_match_alt) # Fetch by an alternate version of the \"NodeSpecs\" object" ] }, { "cell_type": "markdown", "id": "fe62025c-ec6c-4d2c-b084-c4bf81e2c488", "metadata": {}, "source": [ "_Likewise for the \"Person\" node:_" ] }, { "cell_type": "code", "execution_count": 20, "id": "472dc9fe-e813-4e1d-b609-e5b50e15fe7c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query_extended(). Query:\n", " MATCH (n) WHERE (id(n) = 3471) RETURN n\n", "\n", " flatten: True , fields_to_exclude: ['internal_id', '_node_labels']\n" ] }, { "data": { "text/plain": [ "[{'name': 'Julian'}]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.get_nodes(neo_person) # Fetch by the internal database ID" ] }, { "cell_type": "code", "execution_count": 21, "id": "46a506f4-f269-4fe8-8de4-8054bf3fe81b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query_extended(). Query:\n", " MATCH (n :`Person` {`name`: $n_par_1}) RETURN n\n", "Data binding:\n", " {'n_par_1': 'Julian'}\n", "\n", " flatten: True , fields_to_exclude: ['internal_id', '_node_labels']\n" ] }, { "data": { "text/plain": [ "[{'name': 'Julian'}]" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.get_nodes(person_match) # Fetch by \"NodeSpecs\" object returned by the match() method" ] }, { "cell_type": "code", "execution_count": 22, "id": "c2fbec81-aa29-4a3a-98c0-bc58c494faad", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query_extended(). Query:\n", " MATCH (n :`Person` ) WHERE (n.name = 'Julian') RETURN n\n", "\n", " flatten: True , fields_to_exclude: ['internal_id', '_node_labels']\n" ] }, { "data": { "text/plain": [ "[{'name': 'Julian'}]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.get_nodes(person_match_alt_1)" ] }, { "cell_type": "code", "execution_count": 23, "id": "039eb3b9-f60a-4b6d-bc39-015dfd5ad8db", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query_extended(). Query:\n", " MATCH (n :`Person` {`name`: $n_par_1}) RETURN n\n", "Data binding:\n", " {'n_par_1': 'Julian'}\n", "\n", " flatten: True , fields_to_exclude: ['internal_id', '_node_labels']\n" ] }, { "data": { "text/plain": [ "[{'name': 'Julian'}]" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.get_nodes(person_match_alt_2)" ] }, { "cell_type": "code", "execution_count": null, "id": "644d0607-a87b-4b6d-a988-87f4da7411e4", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "987e5954-bb97-4fca-8a21-042b821fe462", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "6ba618c4-5994-42fb-ae74-a9cb4557ab30", "metadata": {}, "source": [ "## If you know the Cypher query language, and simply want to run a generic query, no problem!" ] }, { "cell_type": "code", "execution_count": 24, "id": "9ae1ad12-4622-42f0-a0a3-b0bb1654b54f", "metadata": {}, "outputs": [], "source": [ "q = '''MATCH (p :Person) -[:OWNS] -> (c :Car) -[OWNED_BY] -> (p)\n", " RETURN p.name, c.color, c.make\n", " ''' # This query will verify the forward and reverse links that we created earlier" ] }, { "cell_type": "code", "execution_count": 25, "id": "b5c73d75-c156-47c0-92a4-a4cc1867a508", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query(). Query:\n", " MATCH (p :Person) -[:OWNS] -> (c :Car) -[OWNED_BY] -> (p)\n", " RETURN p.name, c.color, c.make\n", " \n", "\n", " single_row: False , single_cell: `` , single_column : ``\n" ] }, { "data": { "text/plain": [ "[{'p.name': 'Julian', 'c.color': 'white', 'c.make': 'Toyota'}]" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.query(q) # Run the query; by default, it will return a list of records (each record is a dict)" ] }, { "cell_type": "code", "execution_count": 26, "id": "405b2451-007b-4748-b417-3e29cdc1bd3c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In update_query(). Query:\n", " MATCH (c :Car) -[OWNED_BY] -> (p :Person {name: 'Julian'})\n", " SET c.color = 'red'\n", " \n", "\n", " In update_query(). Attributes of ResultSummary object:\n", " metadata -> {'query': \"MATCH (c :Car) -[OWNED_BY] -> (p :Person {name: 'Julian'})\\n SET c.color = 'red'\\n \", 'parameters': {}, 'server': , 't_first': 18, 'fields': [], 'bookmark': 'FB:kcwQvb2+baJ+TrKHXmXfUdIVwsoAB6BkkA==', 'stats': {'contains-updates': True, 'properties-set': 1}, 'type': 'w', 't_last': 0, 'db': 'neo4j'}\n", " server -> \n", " database -> neo4j\n", " query -> MATCH (c :Car) -[OWNED_BY] -> (p :Person {name: 'Julian'})\n", " SET c.color = 'red'\n", " \n", " parameters -> {}\n", " query_type -> w\n", " plan -> None\n", " profile -> None\n", " notifications -> None\n", " counters -> {'_contains_updates': True, 'properties_set': 1}\n", " result_available_after -> 18\n", " result_consumed_after -> 0\n" ] }, { "data": { "text/plain": [ "{'_contains_updates': True, 'properties_set': 1, 'returned_data': []}" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q_paint_car_red = '''MATCH (c :Car) -[OWNED_BY] -> (p :Person {name: 'Julian'})\n", " SET c.color = 'red'\n", " ''' # Paint all of Julian's cars red!\n", "\n", "result = db.update_query(q_paint_car_red) # It returns a dict of info about what it did\n", "\n", "result" ] }, { "cell_type": "code", "execution_count": 27, "id": "478b27f5-bfa1-4e15-8a47-3dd1812bc841", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "In query(). Query:\n", " MATCH (p :Person) -[:OWNS] -> (c :Car) -[OWNED_BY] -> (p)\n", " RETURN p.name, c.color, c.make\n", " \n", "\n", " single_row: False , single_cell: `` , single_column : ``\n" ] }, { "data": { "text/plain": [ "[{'p.name': 'Julian', 'c.color': 'red', 'c.make': 'Toyota'}]" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.query(q) # Re-run the earlier query (to verify the forward and reverse links); notice how the car is now red" ] }, { "cell_type": "code", "execution_count": null, "id": "b59c0ff6-86cf-4378-8733-ebc85090ee4e", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 5 }