To demonstrate how the select()-step is used, we wil create a table which presents how people are experts in applications and how those applications in turn realize business capabilities.
When creating a table using the select()-step, we use the select()-step to refer back to steps we have stored along the way. While traversing, the steps are stored for later access using the as()-step. The as()-step gives a label to the step by which it can be accessed later. When using the select()-step to create a table, each of the selected steps from the traversal will correspond to a column in the table. The names of the columns will correspond to the labels of the selected steps. The components in the selected steps will typically be components or references, so we need to specify which properties of the components we wish to display in the table cells. This can be done by using what we call a by()-step. One by()-step can be provided for each of the selected steps.
This might have been a lot to take in, so let's look at a query which uses everything we just learnt. The following query finds all components in the organization, filters away everything which is not of type "Person", gives this step in the query the label "Person" using the as()-step, follows all outgoing references of type "Is Expert In", filters away everything which is not of type "Application", gives this step the label "Application" using the as()-step, follows all incoming references of type "Is Realized By", filters away everything which is not of type "Business Capability", gives this step the label "Business Capability", selects the steps "Person", "Application" and "Business Capability" using the select()-step, specifies that the "Person"-step should be presented using its "name" property, that the "Application"-step should be presented using its "name" property, and that the "Business Capability" step should be presented using its "name" property.
g.V(). hasLabel('Person').as('Person'). out('Is Expert In'). hasLabel('Application').as('Application'). in('Is Realized By'). hasLabel('Business Capability').as('Business Capability'). select('Person', 'Application', 'Business Capability'). by('name'). by('name'). by('name')
Notice how the first by()-step specifies how the first selected step should be presented, the second by()-step specifies how the second step should be presented, and so on. In the example above, all the steps should be presented using the same property, so in this case one by()-step would have been enough.
Running the query we just presented, it becomes apparent that the table produced by the select-step displays each permutation of Person, Application and Business Capability in different rows, rather than for instance showing all applications and business capabilities corresponding to each Person in a single row.
Another thing worth noticing is that the result table does not have any rows for components of type Person for which an Application or Business Capability cannot be found. In those cases one might rather have expected that there be some empty cells in the table, for instance. This happens because the traversal history in a graph query is always stored in the current selection of elements. Because of this, all traversal steps in Gremlin are also filtering the traversal history. This means that even if the current selection is stored as "Person" in the beginning of the query, when we then follow outgoing references, some of the components in the initial selection might not have any outgoing refereces, which means that from the selection of components after traversing the outgoing references, only the previous steps of those components' histories can be accessed using the select()-step.
To avoid all the pitfalls of using the select-step one can rather use the project()-step, which we will learn about next.