Selection set

On its own, selection set is a GraphQL specific term. For example, when you execute a query, you have the operation:

query {
    myOperation
}

And you also have a selection set, such as the following:

query {
    myOperation {
        field1
        field2
    }
}

In this case, this snippet is the selection set:

{
    field1
    field2
}

When using the OGM, you do not have to provide a selection set by default. Doing so would make using the OGM feel more like querying the GraphQL schema directly, when the OGM is designed as an abstraction over it. This is achieved by automatically generated basic selection sets.

Given the following type definition:

type Movie {
    id: ID
    name: String
    genres: [Genre!]! @relationship(type: "IN_GENRE", direction: OUT)
    customCypher: String! @cypher(statement: "RETURN someCustomData")
}

type Genre {
    name: String
}

Neither relationship fields nor custom Cypher fields are included in the generated selection set, as they could be computationally expensive. So, given the type definition above, the generated selection set would be:

{
    id
    name
}

This means that, by default, when querying for node(s), you only get the .id and .name properties returned. If you want to select more fields, you can either define a selection set at execution time or as a static on the Model, as described in the following section.

Selection set at execution time

Using this approach, you can pass in a selection set every time you interact with the OGM. This is an appropriate approach if the selection set is going to be different every time you ask for data.

Here is an example:

const { OGM } = require("@neo4j/graphql-ogm")
const neo4j = require("neo4j-driver");

const driver = neo4j.driver(
    "bolt://localhost:7687",
    neo4j.auth.basic("username", "password")
);

const typeDefs = `
    type Movie {
        id: ID
        name: String
        genres: [Genre!]! @relationship(type: "IN_GENRE", direction: OUT)
        customCypher: String! @cypher(statement: "RETURN someCustomData")
    }

    type Genre {
        name: String
    }
`;

const ogm = new OGM({ typeDefs, driver });
const Movie = ogm.model("Movie");

const selectionSet = `
    {
        id
        name
        genres {
            name
        }
        customCypher
    }
`;

ogm.init().then(() => {
    Movie.find({ selectionSet }).then((movies) => {
        // work with movies
    })
});

Note that the argument selectionSet is passed every invocation of the Movie.find() function.

Setting a default selection set

Using this approach, you can assign a selection set to a particular Model, so that whenever it is queried, it always returns those fields by default. This is useful if the generated selection set doesn’t give enough data, but you don’t need the selection set to be dynamic on each request.

Here is an example of this:

const { OGM } = require("@neo4j/graphql-ogm")
const neo4j = require("neo4j-driver");

const driver = neo4j.driver(
    "bolt://localhost:7687",
    neo4j.auth.basic("username", "password")
);

const typeDefs = `
    type Movie {
        id: ID
        name: String
        genres: [Genre!]! @relationship(type: "IN_GENRE", direction: OUT)
        customCypher: String! @cypher(statement: "RETURN someCustomData")
    }

    type Genre {
        name: String
    }
`;

const ogm = new OGM({ typeDefs, driver });
const Movie = ogm.model("Movie");

const selectionSet = `
    {
        id
        name
        genres {
            name
        }
        customCypher
    }
`;

Movie.selectionSet = selectionSet;

ogm.init().then(() => {
    Movie.find().then((movies) => {
        // work with movies
    })
});

Note that despite not passing this selection set into Movie.find(), the requested fields return on each request.