GraphGists

Domain

A product catalog is a collection of products, their categories, manufacturers with their pricing information. Products can be sold separately, included in one or more catalogs or used as substitute products

You can perform the following operations on a product: Create, Update, Delete (Not recommended, deactivate instead), Deactivate (We should deactivate products that are no longer available instead of deleting them, because they are included in past orders, quotes, or opportunities.), Search etc.

A store organizes its Products OF_TYPE Category into one or more Catalogs. A Catalog thus becomes a hierarchy of Categories. A Category can be PARENT of one or more child categories. This lending itself naturally to be modeled as a graph. Each Product and Category can have distinct set of attributes than others which also fit nicely into property graph model (otherwise would require a EAV - Entity Attribute Value relational model).

A Product can be SUBSTITUTE_FOR another Product. A product can have one or more MODELs, each model has PRICING associated with it. This is not a complete solution for all the product catalog use cases but provides a good starting point. I will slowly keep modelling more use cases.

Domain Model

Setup

The sample data set uses Bicycle catalog.

Try other queries yourself!

Use Cases

All catalogs

MATCH (c:Catalog) RETURN c.name AS Catalogs

All categories by Depth

MATCH p=(cats:Category)-[:PARENT|PARENT*]->(cat:Catalog)
WHERE cat.name='Summer Outdoor Bicycle Catalog'
RETURN LENGTH(p) AS Depth, COLLECT(cats.name) AS Categories
ORDER BY Depth ASC

All categories of a given level

MATCH p=(cats:Category)-[:PARENT*]->(cat:Catalog)
WHERE cat.name='Summer Outdoor Bicycle Catalog' AND length(p)=1
RETURN cats.name AS CategoriesOfGivenLevel
ORDER BY CategoriesOfGivenLevel

All sub-categories of a given category

MATCH p=(cats:Category)-[:PARENT]->(parentCat:Category), (parentCat)-[:PARENT*]->(c:Catalog)
WHERE parentCat.name='Road Bikes' AND c.name='Summer Outdoor Bicycle Catalog'
RETURN collect(cats.name) AS SubCategories

All Parent and their child categories

MATCH p=(child:Category)-[:PARENT*]->(parent)
RETURN parent.name, collect(child.name)

All parent and their IMMEDIATE children

MATCH p=(child:Category)-[:PARENT]->(parent)
RETURN labels(parent), parent.name, collect(child.name)

All products of a given category

MATCH (p:Product)-[:OF_TYPE]->(c:Category)
WHERE c.name='Road Bikes'
RETURN p.name

Running low on inventory? Recommend another substitute.

MATCH (p:Product)-[:SUBSTITUTE_FOR]->(other:Product {name:"Single Speed Bike"})
RETURN p.name

Get various models of the selected product

MATCH (p:Product)-[:MODEL]->(m:Model)
WHERE p.name="2013 Fuji Declaration Single Speed City Bike"
RETURN p AS Modles

All Categories and their Products of a given catalog

MATCH (p:Product)-[:OF_TYPE]->(c:Category)-[:PARENT*]->(ctl:Catalog)
WHERE ctl.name='Summer Outdoor Bicycle Catalog'
RETURN c.name AS Category, collect(p.name) AS Products

Time to get the shipping and pricing info so as to calculate the total price to be charged

MATCH (p:Product)-[:MODEL]->(m:Model)-[:PRICING]->(price:Price)
WHERE p.name="2013 Fuji Declaration Single Speed City Bike" AND m.type="Large" AND price.validFrom <= timestamp() AND price.validUntil >= timestamp()
RETURN price.list AS ListPrice, price.retail AS RetailPrice, m.height AS Height, m.weight AS Weight

All the categories of a given product in the given catalog

MATCH (p:Product)-[:OF_TYPE]->(c:Category)-[:PARENT*]->(ctl:Catalog)
WHERE p.name='Kids Road Bike' AND ctl.name='Summer Outdoor Bicycle Catalog'
RETURN c.name

Manufacturers and their products

MATCH (m:Manufacturer)<-[:MANUFACTURED_BY]-(p:Product)
RETURN m.name AS Manufacturer, collect(p.name) AS Products