Complex Queries CouchDB with Hyperledger

Paul Marriott
3 min readMay 16, 2021

--

When you start your blockchain journey you inevitably run into the question of how to model relationships within your implementation.

Blockchain Hyperledger Fabric (Fabric) storage is not based on a relational model, data has a key and then a ‘lump’ of data. Thinks of a very long single table with one key for a record and the record data being a blob of text. Therefore complex relationships between data items is not possible right out of the box. You have to be smarter than the traditional developer mindset.

Firstly the ‘lump’ or blob of data can itself be structured, follow the tutorials and embrace using JSON to turn you data into a semi-structured format. For example if your project was a database of rental cars then the number plate could be the unique identifier that the blockchain uses to reference each car. You then model the make, model, color, mileage, capacity as a JSON object like so.

NUMBER PLATE: MYSP04T1

“make”: “Audi”, “model”: “R8”, “color”: “blue”, “mileage”: “8000”, “capacity”: “2”

From within chaincode if I wanted to reference the car with number plate “MYSP04T1” I can retrieve the record by its ID but if I wanted to find all cars that are an Audi I would have to do something smarter.

Fabric has two databases to choose from LevelDB and CouchDB. LevelDB is a basic implementation that stores keys and the data against the key. CouchDB allows a more complex model for your data and what you need for complex queries. CouchDB stores the keys and provides the tools to query the JSON data against each key.

Take three vehicles

  • MYBU54T1 — Transport Bus
  • MYSP04T1 — Sports Car
  • MYV4N4T2 — Camper Van

These three are three separate contracts in Fabric with the following JSON data

Transport Bus

{
“_id”: “MYBU54T1”,
“_rev”: “3–7a9c4626b23acb981cb161809516b717”,
“make”: “VW”,
“model”: “Transporter”,
“color”: “green”,
“mileage”: “27050”,
“capacity”: “2”,
“MaintenanceSchedule”: [
“Every5000”,
“OilFilter”,
“AirFilter”,
“Drive”
],
“TripHistory”: [
{
“TripID”: “1000007”,
“Type”: “PrivateHire”,
“StartMiles”: “20000”,
“FinishMiles”: “27050”
},
{
“TripID”: “0”,
“Type”: “Purchase”,
“StartMiles”: “2000”,
“FinishMiles”: “20000”
}
]
}

Sports Car

{
“_id”: “MYSP04T1”,
“_rev”: “2–875d3d939c05c425382830093e4a1c76”,
“make”: “Audi”,
“model”: “R8”,
“color”: “blue”,
“mileage”: “8000”,
“capacity”: “2”,
“MaintenanceSchedule”: [
“Every1000”,
“OilFilter”,
“AirFilter”
],
“TripHistory”: [
{
“TripID”: “1000099”,
“Type”: “PrivateHire”,
“StartMiles”: “7100”,
“FinishMiles”: “8000”
},
{
“TripID”: “1000097”,
“Type”: “Maintenance”,
“StartMiles”: “2000”,
“FinishMiles”: “7050”
},
{
“TripID”: “0”,
“Type”: “Purchase”,
“StartMiles”: “2000”,
“FinishMiles”: “2000”
}
]
}

Camper Van

{
“_id”: “MYV4N4T2”,
“_rev”: “3-e6c325ad8ded694883187fd1ad6af1cc”,
“make”: “VW”,
“model”: “Camper”,
“color”: “green”,
“mileage”: “9000”,
“capacity”: “2”,
“MaintenanceSchedule”: [
“Every1000”,
“OilFilter”,
“AirFilter”,
“CampingMaint”
],
“TripHistory”: [
{
“TripID”: “1000009”,
“Type”: “PrivateHire”,
“StartMiles”: “7100”,
“FinishMiles”: “9000”
},
{
“TripID”: “1000007”,
“Type”: “Maintenance”,
“StartMiles”: “2000”,
“FinishMiles”: “7050”
},
{
“TripID”: “0”,
“Type”: “Purchase”,
“StartMiles”: “2000”,
“FinishMiles”: “2000”
}
]
}

Three queries can be generated from this data using CouchDB

  1. What vehicles are make VW (expected to get two results)
  2. What vehicles are subject to a Maintenance schedule of every 1000 miles (expected to get two results)
  3. What vehicles have a TripID of 1000007 (expected to get two results)

Solution 1

In CouchDB the following query gives two results. The match is a simple one, find the field ‘make’ and return records that have a value of ‘VW’

{
“selector”: {
“make”: {
“$eq”: “VW”
}
}
}

Solution 2

This solution searches the array of MaintenanceSchedule in each record and returns any records that have a matching entry of ‘Every1000’

{
“selector”: {
“MaintenanceSchedule”: {
“$all”: [
“Every1000”
]
}
}
}

Solution 3

This one was harder to find. Look inside the repeating segment TripHistory at the field TripId for any entries with a value 1000007

{
“selector”: {
“TripHistory”: {
“$elemMatch”: {
“TripID”: “1000007”
}
}
}
}

The above shows how the three queries can be used to pull a list of records with matching entries using CouchDB.

--

--

No responses yet