Search code examples
sparqlrelationshiprdf

SPARQL: How to retrieve a 1:N relationship?


After learning the basics of SPARQL I'm still trying to make sense of 1:N relationships. How can I retrieve an object with all its relationships as a single record?

For example, I have a Project linked to two Topics. And I try to retrieve it with:

        SELECT ?projName ?topic ?topicName {
            ?proj hasName ?projName .
            ?proj hasTopic ?topic .
            ?topic hasName ?topicName .
            FILTER (?proj = <$uri>) .
        }

But what I get is:

result: [
  [
    projName: "My Project"
    topic: "TOPIC1_URI"
    topicName: "First Topic"
  ],
  [
    projName: "My Project"
    topic: "TOPIC2_URI"
    topicName: "Second Topic"
  ]
]

But I would want to get it as:

result: [
  projName: "My Project"
  topics: [
    [
      topic: "TOPIC1_URI"
      topicName: "First Topic"
    ],
    [
      topic: "TOPIC2_URI"
      topicName: "Second Topic"
    ]
  ]
]

How could I achieve this? I don't know what I'm missing but I don't see how to do this with SPARQL.

Thanks a lot in advance


Solution

  • As you can read here, the result of a SELECT SPARQL query is a set of bindings, i.e., assignments of values to the free variables of the query. You can think of such bindings as a matrix or a table, like for SQL queries, whose attributes are the variables' names. But you can't arrange such variables bindings as you wish if you have just a matrix for representing them.

    What you can do is to collect all data about topics in a single variable using the GROUP_CONCAT function. For example:

    SELECT
      ?projName
      (GROUP_CONCAT(?topicData; separator=", ") AS ?topics)
    WHERE {
      ?proj hasName ?projName .
      ?proj hasTopic ?topic .
      ?topic hasName ?topicName .
      FILTER (?proj = <$uri>) .
      BIND(CONCAT(?topic, ": ", ?topicName) AS ?topicData)
    }
    GROUP BY ?projName
    

    But remember that the values assigned to ?topics will be strings, not JSON arrays:

    result: [
      projName: "My Project"
      topics: "TOPIC1_URI: First Topic, TOPIC2_URI: Second Topic"
    ]
    

    Clearly you can choose other separators than ": " and ", ".