Search code examples
reactjsgraphqlapollohasura

How to query only objects containing each element from the array given as a variable using Hasura?


I have a table 'Students' in my db(postgress with Hasura) with relation many-to-many with 'Subjects':

type Student = {
    id: uuid
    name: String
    subjects: [subject]
}

type Subject = {
    id: uuid
    name: String
}

I have a Static QUERY1:

query FilteredStudents($subjects: [String!]) {
    students(where: { subjects: { name: { _in: $subjects } } }) {
        id
        name
    }
}

e.g.:

$subjects = ['Math', 'English', 'Physics']

It will find all the students that attend to ANY of those classes. e.g.:

const student1 = {
   id: 1,
   name: 'Mike',
   subjects: ['Physics', 'Chemistry']  // subjects mapped to names for simplicity
}

My problem is that I want another query which will find all the students that attend to EACH of those classes.

So it shouldn't fetch student1, but should fetch students like this:

const student2 = {
   id: 2,
   name: 'Walt',
   subjects: ['Math', 'English', 'Physics', 'Some', 'other', 'subjects']  // subjects mapped to names for simplicity
}

My only idea was to create dynamic queries like this:
Dynamic QUERY2 (a new query is generated (on runtime) every time the $subject array changes):

query FilteredStudents {
    students(where: { _and: [
        subjects: { name: { _eq: "Math" } }
        subjects: { name: { _eq: "English" } } 
        subjects: { name: { _eq: "Physics" } } 
    ]}) {
        id
        name
    }
}

But I would really want to avoid that and find some static solution. Is there a way to achieve this using filters offered by Hasura? (https://hasura.io/docs/1.0/graphql/manual/queries/query-filters.html#)


Solution

  • I can name your QUERY2 as static already and QUERY1 as dynamic - 1st is parametrized, 2nd is hardcoded.

    You can construct and pass as variable entire where object for both.

    You can read this and use _not with _nin to do the same (as '_and' usage). It stil will be a dynamic condition because where is an input type ... and almost the same condition object creation complexity.

    update

    const subset = ['Math', 'English'];
    
    const condition = { _and: [] };
    subset.map( el => {
      condition._and.push( {
        subjects: { name: { _eq: el } } 
      });
    });
    
    callSomeLazyQuery( { variables: {
      where: condition 
    } );
    

    the same should be valid

    const condition = {
      _not: { 
        _and: [] 
      }
    };
    subset.map( el => {
      condition._not._and.push( {
        subjects: { name: { _nil: el } } 
      });
    });