0
votes

I am trying to model a trading network where accounts can trade multiple items in single trade. I'd like to use neo4j to quickly be able to identify and visualize account behavior, and the movement of specific items

Our mongodb documents look somewhat like this

{
    _id: 1233 // doc id
    date: ISODate("2015-05-01T01:00:00"),
    trade_id: 21312 
    account: 'joe'
    to_account: 'tim' 
    items:
    [
       { name: 'oil',count: '5' },
       { name: 'sunscreen', count: 1}
    ] 
},
{
    _id: 1234 // doc id
    date: ISODate("2015-05-01T01:00:00"),
    trade_id: 21312 
    account: 'tim'
    to_account: 'joe' 
    items:
    [
       { name: 'peas',count: '100' },
    ] 
}

What would be the best structure for this within a neo4j database? I am struggling with how to best deal with the nature of the arrays as I'd like to be able to ask the db, to list me all accounts that have traded 'sunscreen' for 'peas'.

Thanks.

2

2 Answers

1
votes

I would modify @TimKuehn's data model a bit to make it more "graphy". Since you are likely to have a lot of purchases of the same items, you should just have a reusable Item node instance for each product. The ITEM relationships should contain the purchase-specific data (like the item count).

For example:

CREATE (trade:Trade {id: 1233, 
                     date: "2015-05-01T01:00:00", 
                     trade_id: 21312,
                     account: 'joe',
                     to_account: 'tim'})

MERGE (oil:Item {name: 'oil'})
MERGE (sunscreen:Item {name: 'sunscreen'})

CREATE (trade)-[:ITEM {count: 5}]->(oil)
CREATE (trade)-[:ITEM {count: 1}]->(sunscreen)

The MERGE clauses avoid creating duplicate Item nodes. You'd probably also want to also create an appropriate uniqueness constraint to ensure Item uniqueness (and to speed up certain queries).

This model greatly reduces the number of Item nodes needed.

1
votes

An array is a set of records - which in Neo4j would correspond to nodes with the same label.

A candidate design would be a set of "Trade" and "Item" nodes like so:

CREATE (trade:Trade {id: 1233, 
                     date: "2015-05-01T01:00:00", 
                     trade_id: 21312,
                     account: 'joe',
                     to_account: 'tim'})

CREATE (itm1:Item {name: 'oil',       count: 5})
CREATE (itm2:Item {name: 'sunscreen', count: 1})

CREATE (trade)-[:ITEM]->(itm1)
CREATE (trade)-[:ITEM]->(itm2)

the ":Trade" nodes would be the enclosing values, and the ":Item" nodes would correspond to the "item" array elements.

To get the values back - do a MATCH() with the relationship between the ":Trade" and ":Item" nodes using the :ITEM relationship - like so:

MATCH (trade:Trade)-[ritm:ITEM]->(itm:Item)
RETURN trade, ritm, itm

UPDATE This version splits the account info into their own set of labeled nodes and stores the item quantities in their own set of labeled nodes. This follows a more "RDB" way of looking at things. This also assumes there's item-line specific information beyond the qty that needs to be tracked.

// Ensure the accounts exist

MERGE (fromacct:Account {account: 'joe'})
MERGE (toacct:Account   {account: 'tim'})

// Ensure the items exist

MERGE (item1:Item {name: 'oil})
MERGE (item2:Item {name: 'sunscreen'})

// Create the trade transaction

CREATE (trade:Trade {id: 1233,
                     date: "2015-05-01T01:00:00", 
                     trade_id: 21312
                     })

// Create the item line records

CREATE (itemline1:ItemLine {count: 5})
CREATE (itemline2:ItemLine {count: 2})

// link the trade to the item lines

CREATE (trade)-[:ITEMLINE]->(itemline1)
CREATE (trade)-[:ITEMLINE]->(itemline2)

// link the item lines to the items

CREATE (itemline1)-[:ITEM]->(item1)
CREATE (itemline2)-[:ITEM]->(item2)

// link the trade to the items

CREATE (trade)-[:ITEM]->(item1)
CREATE (trade)-[:ITEM]->(item2)