Prev |  | Next

## 9.2. A sample app using traversals and indexes

For detailed documentation on the concepts used here, see Section 19.3, “Indexes” and Section 19.5, “Traversals”.

This example shows you how to get started building something like a simple invoice tracking application with Neo4j.

We start out by importing Neo4j, and creating some meta data that we will use to organize our actual data with.

    from neo4j import GraphDatabase, INCOMING, Evaluation

    # Create a database
    db = GraphDatabase(folder_to_put_db_in)

    # All write operations happen in a transaction
    with db.transaction:

        # A node to connect customers to
        customers = db.node()

        # A node to connect invoices to
        invoices = db.node()

        # Connected to the reference node, so
        # that we can always find them.
        db.reference_node.CUSTOMERS(customers)
        db.reference_node.INVOICES(invoices)

        # An index, helps us rapidly look up customers
        customer_idx = db.node.indexes.create('customers')

### 9.2.1. Domain logic

Then we define some domain logic that we want our application to be able to perform. Our application has two domain objects, Customers and Invoices. Let’s create methods to add new customers and invoices.

    def create_customer(name):
        with db.transaction:
            customer = db.node(name=name)
            customer.INSTANCE_OF(customers)

            # Index the customer by name
            customer_idx['name'][name] = customer
        return customer

    def create_invoice(customer, amount):
        with db.transaction:
            invoice = db.node(amount=amount)
            invoice.INSTANCE_OF(invoices)

            invoice.RECIPIENT(customer)
        return customer

In the customer case, we create a new node to represent the customer and connect it to the customers node. This helps us find customers later on, as well as determine if a given node is a customer.

We also index the name of the customer, to allow for quickly finding customers by name.

In the invoice case, we do the same, except no indexing. We also connect each new invoice to the customer it was sent to, using a relationship of type `SENT_TO`.

Next, we want to be able to retrieve customers and invoices that we have added. Because we are indexing customer names, finding them is quite simple.

    def get_customer(name):
        return customer_idx['name'][name].single

Lets say we also like to do something like finding all invoices for a given customer that are above some given amount. This could be done by writing a traversal, like this:

    def get_invoices_with_amount_over(customer, min_sum):
        def evaluator(path):
            node = path.end
            if node.has_key('amount') and node['amount'] > min_sum:
                return Evaluation.INCLUDE_AND_CONTINUE
            return Evaluation.EXCLUDE_AND_CONTINUE

        return db.traversal()\
                 .relationships('RECIPIENT', INCOMING)\
                 .evaluator(evaluator)\
                 .traverse(customer)\
                 .nodes

### 9.2.2. Creating data and getting it back

Putting it all together, we can create customers and invoices, and use the search methods we wrote to find them.

    for name in ['Acme Inc.', 'Example Ltd.']:
       create_customer(name)

    # Loop through customers
    for relationship in customers.INSTANCE_OF:
       customer = relationship.start
       for i in range(1,12):
           create_invoice(customer, 100 * i)

    # Finding large invoices
    large_invoices = get_invoices_with_amount_over(get_customer('Acme Inc.'), 500)

    # Getting all invoices per customer:
    for relationship in get_customer('Acme Inc.').RECIPIENT.incoming:
        invoice = relationship.start

Copyright © 2012 Neo Technology

Prev | Up | Next
| Home |