Trying to filter linked item list with the CDA

Hi there,

I’m not sure if there’s some way to do what I want to do or it’s just a limitation. Let me describe my use case:

  • We have a main model “Posts” with 6000+ records
  • We want to place a series of posts into different feature groups
  • Within these feature groups we want to (1) be able to filter the posts by values on the post model and (2) easily control the display order with the drag-and-drop interface.
    I can’t seem to come up with an ideal way of doing this. If I set up the post model with a multiple link field to the feature group model then I can’t easily control the display order.
    What I’ve tried to do is set up the feature group model to have a multiple link field to the pages which allows me the nice visible order, but then I can’t do the additional filtering we need easily, there’s no visible way to do complex filtering like this:
  allFeatureGroups(filter: $groupsFilter) {
    id
    posts(filter: $thisDoesntWork) {
      ...PostDetailsFragment
    }
  }

I could make this happen by getting the groups, building an array of post ID’s and a second query with the additional filters on, but that’s pretty inefficient. Is there something I’m missing or should I just do that.

Thanks!

Hey @ryan.dunn,

Welcome to the Dato forum!

If I’m understanding your use case right, you can do this with our Inverse Relationships.

I invited you to an example project via email, but in brief, setting that up will allow you make a query like this:

query MyQuery {
  allFeatureGroups(filter: {showThisFeatureGroup: {eq: "true"}}) {
    id
    name
    _allReferencingPosts(filter: {showThisPost: {eq: "true"}}) {
      id
      title
      showThisPost
    }
  }
}

The outer allFeatureGroups filters the feature groups (and you can order them however you want, though that’s not in the query). The nested _allReferencingPosts is the inverse relationship of all the Posts that link to this Feature Group, and you can filter on a field of the linking Post (in this case, their showThisPost field).

That gets you a response like:

{
  "data": {
    "allFeatureGroups": [
      {
        "id": "QjPvquQeRvWwRm_6UPD15A",
        "name": "How-To Guides",
        "_allReferencingPosts": [
          {
            "id": "SnrOC9D_RveJUXYpKrCijw",
            "title": "How to use a headless CMS",
            "showThisPost": true
          },
          {
            "id": "PIuUHuJ_Qaq1WJzprf2jfQ",
            "title": "How to change your schema",
            "showThisPost": true
          }
        ]
      },
      {
        "id": "OT0M7wMDRPGxmiwSsEbgvA",
        "name": "Case Studies",
        "_allReferencingPosts": [
          {
            "id": "BoOgw50NSwiRujnm3dW2ew",
            "title": "Ten Jamstack Examples",
            "showThisPost": true
          }
        ]
      },
      {
        "id": "F9xRzJmIQ52Zb6xmW0gTVA",
        "name": "Top 10 Lists",
        "_allReferencingPosts": [
          {
            "id": "BoOgw50NSwiRujnm3dW2ew",
            "title": "Ten Jamstack Examples",
            "showThisPost": true
          },
          {
            "id": "Sw-qh6TrRYC0JoGty24iMA",
            "title": "Top 10 Mistakes Humans Make",
            "showThisPost": true
          }
        ]
      }
    ]
  }
}

The feature groups are hidden if showThisFeatureGroup != true, and the posts are hidden if showThisPost != true.

In the schema, each Post has a Multiple Links field to Feature Groups:

The Feature Group schema is much simpler, only having that one boolean field to filter by:

The magic happens when you edit that model and turn on inverse relationships:


It’s a little counter-intuitive at first, but once you set it up, I think that should do what you want? Or if I’m misunderstanding, can you please provide another example (or link me to your real project)?

Hi Roger, thanks so much for the detailed response.

The inverse relationships are really powerful and useful, but the thing I’m trying to get out of it is the ability to filter AND to give the user drag-and-drop ordering power. So this is our group at the moment (I have two versions of this schema for experimenting, another where we have the inverse relationships you outlined above).

This allows the editor to control the arbitrary viewable order with the very-nice drag-and-drop interface. But we also need to be able to run filters on those items (eg: some posts have active dates, limitations to user types, etc). Right now I can’t see a way to get both with one query because the multiple item links field doesn’t support the query filters.

I know this is quite niche and there are multiple good but just slightly imperfect solutions (eg: using the inverse relationship field and adding an arbitrary order field). I think I’ll probably write it with two queries though (get the groups and their linked field posts, then get the posts by the returned IDs with filters applied). I’d rather not use two queries or make the admins do the ordering manually, but it’s not the end of the world.

Ah, sorry, so you want the drag-and-drop ordering on the Posts themselves, not the Feature Groups? That might be harder then, you’re right :frowning: Apologies for misunderstanding.

As a (imperfect) workaround, here’s a couple ways to avoid having to write two queries:

Workaround #1:

Not sure if you knew this already, but in GraphQL, you can actually make several requests inside the same query, one after another, inside the same API call. They come back at the same time. For example:

query MyQuery {
  allFeatureGroups(filter: {showThisFeatureGroup: {eq: true}}) {
    id
    name
    posts {
      id
      title
    }
  }
  
  onlyShowThesePosts:allPosts (filter: {showThisPost: {eq: true}}) {
    id
  }
}

Will get you:

{
  "data": {
    "allFeatureGroups": [...], // The groups and all posts, in order
    "onlyShowThesePosts": [ // You can then filter on the clientside against this list
      {
        "id": "SnrOC9D_RveJUXYpKrCijw"
      },
      {
        "id": "BoOgw50NSwiRujnm3dW2ew"
      },
      {
        "id": "Sw-qh6TrRYC0JoGty24iMA"
      },
      {
        "id": "PIuUHuJ_Qaq1WJzprf2jfQ"
      }
    ]
  }
}

Although it’s two separate GraphQL statements, it’s still just one API call and the client gets both at the same time, and then you can then filter allFeatureGroups against onlyShowThesePosts without having to make a separate call.

Or Workaround #2:

You can of course also just include the Post fields to filter by inside the query, and do all the filtering clientside, like:

query MyQuery {
  allFeatureGroups(filter: {showThisFeatureGroup: {eq: true}}) {
    id
    name
    posts {
      id
      title
      showThisPost
    }
  }
}

Which becomes:

{
  "data": {
    "allFeatureGroups": [
      {
        "id": "F9xRzJmIQ52Zb6xmW0gTVA",
        "name": "Top 10 Lists",
        "posts": [
          {
            "id": "GNUv20kdQtOslxxzVyaWQw",
            "title": "This post should be hidden",
            "showThisPost": false
          },
          {
            "id": "Sw-qh6TrRYC0JoGty24iMA",
            "title": "Top 10 Mistakes Humans Make",
            "showThisPost": true
          },
          {
            "id": "BoOgw50NSwiRujnm3dW2ew",
            "title": "Ten Jamstack Examples",
            "showThisPost": true
          }
        ]
      },
      {
        "id": "OT0M7wMDRPGxmiwSsEbgvA",
        "name": "Case Studies",
        "posts": [
          {
            "id": "BoOgw50NSwiRujnm3dW2ew",
            "title": "Ten Jamstack Examples",
            "showThisPost": true
          },
          {
            "id": "GNUv20kdQtOslxxzVyaWQw",
            "title": "This post should be hidden",
            "showThisPost": false
          }
        ]
      },
      {
        "id": "QjPvquQeRvWwRm_6UPD15A",
        "name": "How-To Guides",
        "posts": [
          {
            "id": "SnrOC9D_RveJUXYpKrCijw",
            "title": "How to use a headless CMS",
            "showThisPost": true
          },
          {
            "id": "PIuUHuJ_Qaq1WJzprf2jfQ",
            "title": "How to change your schema",
            "showThisPost": true
          },
          {
            "id": "GNUv20kdQtOslxxzVyaWQw",
            "title": "This post should be hidden",
            "showThisPost": false
          }
        ]
      }
    ]
  }
}

Then in JS you can filter out all the posts[] that have showThisPost != true. Yes, that results in a bit of over-fetching, but it should have a minimal performance impact. To your editors it should still work the same, but you just move the filtering logic clientside instead of in GraphQL.


I know neither solution is perfect, though, and I appreciate you illustrating the use case here. Let’s also leave this thread open as a feature request (assuming that is what you meant to post it as) and hope for a better official solution someday. (I agree, being able to apply filters on an array field would be nice). Please remember to vote on the topic at the top (the little blue Vote button) :slight_smile:

1 Like

Thanks for that.

What I ended up doing was like you suggested and doing the additional post filtering client-side to avoid the double request. The feature groups are unlikely to exceed the paginated results limit even with unfiltered results so that should be more than enough for now, with only minimal duplication of logic with the client-side filtering.

1 Like