---
title: "Review queries"
description: "Learn to use Gremlin and Python for transaction analysis and data aggregation in Aerospike Graph."
---

# Review queries

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

This page walks through the four queries in the example application. Each query demonstrates common patterns for traversing and analyzing graph data.

## Query 1: Find transactions by user

This query finds all transactions initiated by Alice:

```python
results = g.V().has("User", "name", "Alice") \

    .out("owns") \

    .out_e("Transaction") \

    .as_("transaction") \

    .in_v() \

    .values("accountId") \

    .as_("receiver") \

    .select("transaction", "receiver") \

    .by("amount") \

    .by() \

    .to_list()

for result in results:

    print(f"Transaction Amount: {result['transaction']}, Receiver Account ID: {result['receiver']}")
```

**How it works:**

1.  `V()` starts at all vertices in the graph
2.  `has("User", "name", "Alice")` filters to the User vertex with name “Alice”
3.  `out("owns")` follows the “owns” edge to Alice’s account
4.  `out_e("Transaction")` traverses outgoing Transaction edges
5.  `as_("transaction")` labels these edges as “transaction” for later reference
6.  `in_v()` moves to the target vertices (receiving accounts)
7.  `values("accountId")` extracts the accountId property
8.  `as_("receiver")` labels these values as “receiver”
9.  `select("transaction", "receiver")` returns both labeled elements
10.  `by("amount")` specifies to return the amount property from the transaction edge
11.  `by()` specifies to return the accountId value as-is
12.  `to_list()` executes the query and returns results as a Python list

**Output example:**

```plaintext
Transaction Amount: 200, Receiver Account ID: A2

Transaction Amount: 456, Receiver Account ID: A3

Transaction Amount: 789, Receiver Account ID: A4
```

This pattern is useful for analyzing a specific user’s transaction history.

## Query 2: Aggregate transaction amounts by account

This query calculates the total amount of outgoing transactions for each account:

```python
results = g.V().has_label("Account") \

    .group() \

    .by("accountId") \

    .by(__.out_e("Transaction").values("amount").sum_()) \

    .to_list()

for result in results:

    print(result)
```

**How it works:**

1.  `V()` starts at all vertices
2.  `has_label("Account")` filters to Account vertices only
3.  `group()` creates groups of vertices
4.  The first `by("accountId")` groups vertices by their accountId property
5.  The second `by()` clause defines what to compute for each group:
    -   `__.out_e("Transaction")` traverses outgoing Transaction edges (the `__` prefix indicates an anonymous traversal)
    -   `values("amount")` extracts the amount property from each transaction
    -   `sum_()` sums all amounts for that account
6.  `to_list()` returns the groups as a dictionary

**Output example:**

```plaintext
{'A1': 2345}

{'A2': 1876}

{'A3': 3012}

{'A4': 987}

{'A5': 2543}
```

This pattern is useful for computing aggregates like totals, averages, or counts grouped by a property.

## Query 3: Find users who sent large transfers

This query finds all users who transferred more than 100 units to Alice:

```python
results = g.V().has("User", "name", "Alice") \

    .out("owns") \

    .in_e("Transaction") \

    .has("amount", P.gte(100)) \

    .out_v() \

    .in_("owns") \

    .value_map("name") \

    .to_list()

for result in results:

    print(f"User: {result}")
```

**How it works:**

1.  `V()` starts at all vertices
2.  `has("User", "name", "Alice")` finds Alice’s User vertex
3.  `out("owns")` follows the “owns” edge to Alice’s account
4.  `in_e("Transaction")` traverses incoming Transaction edges (money coming in)
5.  `has("amount", P.gte(100))` filters to transactions with amount greater than or equal to 100
6.  `out_v()` moves to the source vertices of those transactions (sending accounts)
7.  `in_("owns")` follows “owns” edges backwards to find the owning users
8.  `value_map("name")` returns a map of properties for each user (in this case, just the name)
9.  `to_list()` returns all matching users

**Output example:**

```plaintext
User: {'name': ['Bob']}

User: {'name': ['Charlie']}

User: {'name': ['Diana']}
```

Note that `value_map()` returns property values as lists because vertices can have multiple values for the same property key. To get a single value, you can use `values("name")` instead.

The `P.gte()` predicate (greater than or equal) is one of many comparison operators available:

-   `P.eq()` - equals
-   `P.neq()` - not equals
-   `P.lt()` - less than
-   `P.lte()` - less than or equal
-   `P.gt()` - greater than
-   `P.gte()` - greater than or equal
-   `P.between()` - within a range

This pattern is useful for fraud detection, identifying suspicious transaction patterns, or finding high-value customers.

## Query 4: Retrieve user properties

This query retrieves all properties for Bob:

```python
bob_properties = g.V().has("User", "name", "Bob").value_map().next()

for key, value in bob_properties.items():

    print(f"{key}: {value[0]}")
```

**How it works:**

1.  `V()` starts at all vertices
2.  `has("User", "name", "Bob")` filters to Bob’s User vertex
3.  `value_map()` returns a dictionary of all properties on the vertex
4.  `next()` executes the query and returns the first (and only) result

**Output example:**

```plaintext
userId: U2

name: Bob

age: 35
```

The `value_map()` method returns property values as lists. The code accesses `value[0]` to extract the first (and typically only) value for each property.

If you only need specific properties, you can pass them as arguments:

```python
bob_name_and_age = g.V().has("User", "name", "Bob").value_map("name", "age").next()
```

This pattern is useful for displaying detailed information about a specific entity in your application.

## Key Gremlin concepts

These queries demonstrate several important Gremlin concepts:

**Traversal steps:**

-   `V()` - start at vertices
-   `E()` - start at edges
-   `has()`, `has_label()` - filter by properties or labels
-   `out()`, `in_()` - traverse edges to adjacent vertices
-   `out_e()`, `in_e()` - traverse to adjacent edges
-   `out_v()`, `in_v()` - traverse from edges to vertices
-   `values()` - extract property values
-   `value_map()` - extract all properties as a map

**Terminal steps:**

-   `next()` - return the next result
-   `to_list()` - return all results as a list
-   `iterate()` - execute without returning results

**Modulation:**

-   `as_()` - label a step for later reference
-   `select()` - return labeled elements
-   `by()` - specify how to project or sort elements

**Predicates:**

-   `P.eq()`, `P.gte()`, `P.between()` - comparison operators

**Anonymous traversals:**

-   `__` - start a nested traversal within another step

## Common patterns

The queries demonstrate three common patterns:

1.  Path traversal: Start at a vertex, follow edges to related vertices (Query 1 and 3).
2.  Aggregation: Group vertices or edges and compute summary statistics (Query 2).
3.  Property extraction: Retrieve detailed attributes of specific entities (Query 4).

These patterns form the foundation for more complex graph queries in real applications.

## Clean up

After running the queries, the example drops all vertices and edges:

```python
g.V().drop().iterate()
```

The `drop()` step removes vertices and edges from the graph. This cleans up the data so you can run the example multiple times without creating duplicate entries.

::: undefined
-   I understand how to find transactions by user.
-   I understand how to aggregate transaction amounts.
-   I understand how to filter transactions by amount.
-   I understand how to retrieve vertex properties.
:::

[Previous  
Understand the data model](https://aerospike.com/docs/graph/graph-and-python-basics/step/2/part/0/understand-data-model) [Next  
Modify the graph](https://aerospike.com/docs/graph/graph-and-python-basics/step/3/part/0/mutate-graph)