Multi tenancy in GRANDStack

Hi,

I'm trying to implement multitenancy in a Neo4j database with GRANDStack. Each tenant corresponds to a company and each company will have its own graphql schema.

Researching, I've read that, for now, multitenancy in Neo4j is not supported natively but in Neo4j 4.0 will be available. Until then, I need to implement a workaround. In this thread, Proper way to implement multi-tenancy on Neo4j, david.allen says that a popular way to implement multitenancy is to add a tenant label to the nodes that belong to it.

Having this in mind, the only way I've found to add multiple labels to a node with graphql-neo4j-js is adding an interface with the name of the company, and all the types in the schema should implement it. For example, for the company "TestCompany" the schema would be like:

interface TestCompany {
    _uid: ID!
}

type Employee implements TestCompany {
  _uid: ID!
  email: String!
  name: String
  age: Int
}

This schema will generate a create mutation for Employee that will assign to the node two labels, Employee and TestCompany.

The query for getting all employees that belong to TestCompany would be:

{
  TestCompany {
    ... on Employee {
    	 name
         email
  	}
  }
}

If I want to get a specific employee by its uid:

{
  TestCompany(_uid: "5145f6e2-e8b0-4da0-9cc0-fac7c38f6320") {
    ... on Employee {
    	 name
         email
  	}
  }
}

Everything is ok so far, but the problem appears when I want to filter by some attribute of the employee. For example, if I want to get all employees whose age is 23. So, my first question is:

1. Is there a way to filter in the "on" clause by the Employee attributes?

Assuming there isn't a way to do that, I've tried a workaround that is not very clean, but anyway, I've added a new attribute to the company interface called company_name, and I've hardcoded its value with a Cypher directive like this:

interface TestCompany {
    _uid: ID!
   company_name: String @cypher(statement: "return 'TestCompany' ")
}

type Employee implements TestCompany {
  _uid: ID!
  company_name: String @cypher(statement: "return 'TestCompany' ")
  email: String!
  name: String
  age: Int
}

I've thought that, with this new property, I'd be able to filter the node directly by its company_name (I know that with this approach I'm not filtering by the node label but by the company_name property) like:

{
  Employee(company_name: "TestCompany", age: 23) {
       name
      email
  }
}

But, as explained here https://github.com/neo4j-graphql/neo4j-graphql-js/issues/105, the cypher directive properties are not exposed as filters due to performance reason by default. My second question is:
2. Is there a way to expose the cypher directive property as a filter? Or, can I hardcode the value in the schema without a cypher directive?

Finally, I've tried to solve the multitenancy with this approach, but:

3. Are there better approaches than the described one?

Thank you very much in advance,

1 Like

Thanks to johnymontana I've found a solution. As he said in the docs, in this link, https://grandstack.io/docs/neo4j-graphql-js-middleware-authorization.html#additionallabels, you can specify additional labels with the @additionalLabels directive.
When querying, creating and updating, graphql-neo4j-js will add automatically all the labels included.