# Is there a way to do WHERE NOT CONTAINS?

**URL:** <https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811>\
**Category:** Help\
**Created:** [December 15, 2021, 7:14am UTC](https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811 "2021-12-15T07:14:12Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![ayush-sharma](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.jekyllrb.com/ayush-sharma/32/4200_2.png) [@ayush-sharma](https://talk.jekyllrb.com/u/ayush-sharma)\
**Post date:** [December 15, 2021, 7:14am UTC](https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811/1 "2021-12-15T07:14:12Z")

</div>

Hi,

My Jekyll posts have a `category_list` which contains a list of post categories.

I’m trying to filter posts which CONTAIN `category A` but NOT `category B`.

For example, I want to get posts in the `tech` category which do not contain `games` category.

```auto
{% assign posts = site.posts | where_exp:"item","item.category_list contains 'category A' and item.category_list not contains 'category B'" | sort: 'users' | reverse %}

```

This is obviously not working. I know I can do this using `unless`, but that means I have to change the filter to an `if` condition.

Is there a way to do this using filters only?

---

<div class="post-metadata">

**Author:** ![MichaelCurrin](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.jekyllrb.com/michaelcurrin/32/2340_2.png) [@MichaelCurrin](https://talk.jekyllrb.com/u/MichaelCurrin)\
**Post date:** [December 15, 2021, 8:19pm UTC](https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811/2 "2021-12-15T20:19:23Z")

</div>

> [@ayush-sharma](#):
>
> `and item.category_list not contains`

Can you negate in front instead of in the middle?

```auto
and not item.category_list contains ...

```

You can add brackets for readability

```auto
and not (item.category_list contains ...)

```

---

<div class="post-metadata">

**Author:** ![ayush-sharma](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.jekyllrb.com/ayush-sharma/32/4200_2.png) [@ayush-sharma](https://talk.jekyllrb.com/u/ayush-sharma)\
**Post date:** [December 16, 2021, 9:59am UTC](https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811/3 "2021-12-16T09:59:52Z")

</div>

Welp, that didn’t work ☹

```auto
{% assign posts = site.posts | where_exp:"item","item.languages contains lang and not (item.category_list contains 'adult')" | sort: 'users' | reverse %}

```

```auto
Liquid Exception: Liquid syntax error (line 55): Expected end_of_string but found id in index.md
             Error: Liquid syntax error (line 55): Expected end_of_string but found id
             Error: Run jekyll build --trace for more information.

```

Tried with and without brackets. No joy.

---

<div class="post-metadata">

**Author:** ![pippim](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.jekyllrb.com/pippim/32/4089_2.png) [@pippim](https://talk.jekyllrb.com/u/pippim)\
**Post date:** [December 23, 2021, 2:19am UTC](https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811/4 "2021-12-23T02:19:49Z")

</div>

> [@ayush-sharma](#):
>
> `Error: Run jekyll build --trace for more information.`

It recommended running a trace on the issue. Did you do that? What did the trace say?

---

<div class="post-metadata">

**Author:** ![BillRaymond](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.jekyllrb.com/billraymond/32/5963_2.png) [@BillRaymond](https://talk.jekyllrb.com/u/BillRaymond)\
**Post date:** [January 7, 2022, 6:19am UTC](https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811/5 "2022-01-07T06:19:13Z")

</div>

I’m not in front of the computer to test this, but given you are still trying to make it work, I believe you can just add another `where_exp`. If I’m not mistaken, Liquid will process your filters from left to right. So instead of doing the AND, just do your first `where_exp` and then do the second.

---

<div class="post-metadata">

**Author:** ![ayush-sharma](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.jekyllrb.com/ayush-sharma/32/4200_2.png) [@ayush-sharma](https://talk.jekyllrb.com/u/ayush-sharma)\
**Post date:** [January 8, 2022, 6:54pm UTC](https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811/6 "2022-01-08T18:54:58Z")

</div>

Thanks for the tip, Bill, but it didn’t work. Adding the `not` gives an error:

Filter:

```auto
{% assign posts = site.posts | where_exp:"item","item.category_list not contains 'adult'" | where_exp:"item","item.category_list contains cat" | sort: 'users' | reverse %}

```

```auto
       Jekyll Feed: Generating feed for posts
  Liquid Exception: Liquid syntax error (line 113): Expected end_of_string but found id in index.md
             Error: Liquid syntax error (line 113): Expected end_of_string but found id
             Error: Run jekyll build --trace for more information.

```

Removing the `not` parses correctly, so I’m assuming the `not` keyword is causing the problem.

I’m currently just using an `if` to filter out the results, like this:

```auto
{% if post.category_list contains 'adult' %}
        {% continue %}
{% endif %}

```

… but I wish there was a neater solution.

---

<div class="post-metadata">

**Author:** ![BillRaymond](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.jekyllrb.com/billraymond/32/5963_2.png) [@BillRaymond](https://talk.jekyllrb.com/u/BillRaymond)\
**Post date:** [January 11, 2022, 2:21am UTC](https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811/7 "2022-01-11T02:21:50Z")

</div>

I am back and did some research on this. There is no easy way to do what you are asking for. There is no `not contains` feature in Jekyll. You could do a `!=` for exact matches, but that would mean you have to match a particular string, not an array of strings. Would it be possible for you to move the `category_list` elements to additional YAML data elements? Maybe you could more clearly articulate why you are doing this we can come up with a different solution?

---

<div class="post-metadata">

**Author:** ![ayush-sharma](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.jekyllrb.com/ayush-sharma/32/4200_2.png) [@ayush-sharma](https://talk.jekyllrb.com/u/ayush-sharma)\
**Post date:** [January 12, 2022, 11:47am UTC](https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811/8 "2022-01-12T11:47:18Z")

</div>

So, I have posts which contain a set of categories under `category_list`.

For every category, I iterate over that list and display posts for that category. The code for this is [here](https://gitlab.com/ayush-sharma/to-the-fediverse/-/blob/master/index.md#L117).

Additionally, when displaying posts for a category, I want to avoid posts which contain a particular category, for example “adult”. This is to avoid displaying 18+ posts. To achieve this, I’m currently using an `if` check as on [Line 125](https://gitlab.com/ayush-sharma/to-the-fediverse/-/blob/master/index.md#L125).

The above code combining `for` and `if` is technically correct and working, but it would be a lot neater if I could combine both in a single expression.

---

<div class="post-metadata">

**Author:** ![BillRaymond](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.jekyllrb.com/billraymond/32/5963_2.png) [@BillRaymond](https://talk.jekyllrb.com/u/BillRaymond)\
**Post date:** [January 12, 2022, 9:20pm UTC](https://talk.jekyllrb.com/t/is-there-a-way-to-do-where-not-contains/6811/9 "2022-01-12T21:20:02Z")

</div>

Okay, I see the code and understand where you are coming from. Since adult content is a unique element to your site and [could potentially?] spread across any type of category, my best suggestion is to create a new YAML front matter element.

For example, your new YAML might look like this:

```auto
---
layout: instance
page: /
title: "0q0-xyz"
name: "0q0.xyz"
instance_url: "https://0q0.xyz"
short_description: "Pleroma: An efficient and flexible fediverse server"
description: "Pleroma: An efficient and flexible fediverse server"
admin: "blac_baqu@tuta.xyz"
admin_email: "blac_baqu@tuta.xyz"
statuses: 0
active_users: 0
users: 1
statuses_display: "0"
active_users_display: "0"
users_display: "1"
languages: en
category_list: 
prohibited_content: ""
thumbnail: "https://fed.0q0.xyz/instance/thumbnail.jpeg"
registrations: True
approval_required: False
version: "2.7.2 (compatible; Pleroma 2.4.1)"
created_at: 1639739176.0
adult: true
---

```

Notice the new `adult: true` at the bottom of the post elements.

Now your new code will look something like this:

```auto
{% assign filtered_posts = site.posts | where_exp: "item", "item.category_list contains 'Category A'" | where: "adult", "false" %}

```

or

```auto
{% assign filtered_posts = site.posts | where_exp: "item", "item.category_list contains 'Category A'" | where: "adult", "true" %}

```

I hope this helps.
