问题
I want to see if there is a way to represent/model a nested parent-child relationship in a graph db platform like neo4j or arangodb.
In particular, I am trying to model the contractor/subcontractor relations over multiple contracts:
example contract relations image link
I can see how this can be done using a table where both the parent and the contract are represented. I can't see how to do this in a graph since there can be multiple A-B relations but for different contracts.
回答1:
Using ArangoDB
The best thing to do here is create three collections, and I've created some sample data and sample queries to show you how it can work.
- contracts: A document collection that contains contracts
- companies: A document collection that contains companies
- company_contracts: An edge collection that contains connections between contracts and companies
The goal is to store your contracts and companies in their respective collections and then store the relationshps in the company_contracts edge collection.
Because the companies are reused across multiple contracts, it will therefore be necessary to be able to filter on the relationships, based on the contract code.
Each contract has a key called code
which contains an identifier for that contract (e.g. 'Contract 1' has a code
of 1
).
Note: I've also added a code
field to each company, but that's not necessarily required for this example.
Each relationship that is added to the company_contracts
edge collection will have a key added to it to identify what contract that edge is for, and this key is called contract_code
.
This will be used in your AQL query to ensure you only select edges related to your contract in question.
To create the base data, you run this script in the arangodsh
tool, just start it and then once you've provided your password and are connected, just paste this block of text in to create the sample collections and load some base data.
var contracts = db._create("contracts");
var companies = db._create("companies");
var company_contracts = db._createEdgeCollection("company_contracts");
var contract_1 = contracts.save({_key: "1", title:"Contract 1", code: 1})._id;
var contract_2 = contracts.save({_key: "2", title:"Contract 2", code: 2})._id;
var contract_3 = contracts.save({_key: "3", title:"Contract 3", code: 3})._id;
var company_a = companies.save({_key: "a", title:"Company A", code: "A"})._id;
var company_b = companies.save({_key: "b", title:"Company B", code: "B"})._id;
var company_c = companies.save({_key: "c", title:"Company C", code: "C"})._id;
var company_d = companies.save({_key: "d", title:"Company D", code: "D"})._id;
var company_e = companies.save({_key: "e", title:"Company E", code: "E"})._id;
company_contracts.save(contract_1, company_a, { contract_code: 1});
company_contracts.save(company_a, company_c, { contract_code: 1});
company_contracts.save(company_a, company_b, { contract_code: 1});
company_contracts.save(company_c, company_d, { contract_code: 1});
company_contracts.save(company_c, company_e, { contract_code: 1});
company_contracts.save(contract_2, company_c, { contract_code: 2});
company_contracts.save(contract_2, company_a, { contract_code: 2});
company_contracts.save(company_a, company_b, { contract_code: 2});
company_contracts.save(company_c, company_d, { contract_code: 2});
company_contracts.save(contract_3, company_b, { contract_code: 3});
company_contracts.save(company_b, company_c, { contract_code: 3});
company_contracts.save(company_b, company_a, { contract_code: 3});
Once you've done that, this is an example AQL query you could use to find all relationships for a given contract code:
LET contract_id = FIRST(FOR d IN contracts FILTER d.code == @contract_code RETURN d._id)
FOR v, e, p IN 1..10 OUTBOUND contract_id company_contracts
FILTER p.edges[*].contract_code ALL == @contract_code
RETURN p
If you pass a value of 1
as the value for the contract_code
parameter, you'll get the result as shown by your sample document, and if you provide the values 2
or 3
it will show those results.
The query works by doing two things:
- The
LET
query finds the_id
of the contract you're interested in - The
GRAPH
query then finds all outbound connections from that contract, and it applies a filter toALL
edges in each path coming out of that contract, ensuring every single edge has acompany_code
key that matches the contract code you're working with
This FILTER ... ALL
condition ensures you only get edges related to your contract.
The view of the results looks like this in the ArangoDB graph viewer for the results for Contract 1:
来源:https://stackoverflow.com/questions/56034784/how-to-represent-non-unique-parent-child-relationship-as-graph