Skip to content

There was no example of how to negate the in operator in the docs. …#2360

Merged
ppekrol merged 4 commits intoravendb:mainfrom
slidwell44:negating-the-in-operator
Mar 30, 2026
Merged

There was no example of how to negate the in operator in the docs. …#2360
ppekrol merged 4 commits intoravendb:mainfrom
slidwell44:negating-the-in-operator

Conversation

@slidwell44
Copy link
Copy Markdown
Contributor

…This is not obvious compared to how you would use the in operator

Issue link

https://issues.hibernatingrhinos.com/issue/RDoc-...

Additional description

Include details of the change made, paste screenshots if necessary, and add anything that may be useful for the reviewers.

Type of change

  • Content - docs
  • Content - cloud
  • Content - guides
  • Content - start pages/other
  • New docs feature (consider updating /templates or README)
  • Bug fix
  • Optimization
  • Other

Changes in docs URLs

  • No changes in docs URLs
  • Articles are restructured, URLs will change, mapping is required (update /scripts/redirects.json, set the Documents Moved PR label)

Changes in UX/UI

  • No changes in UX/UI
  • Changes in UX/UI (include screenshots and description)

…This is not obvious compared to how you would use the `in` operator
@ppekrol ppekrol requested a review from Danielle9897 March 24, 2026 19:12
<TabItem>
```csharp
from "Companies"
where exists(Name) and not Name in ("The Big Cheese", "Unknown company name")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to use true - this is what we do in the Client API

from "Companies"
where true and not Name in ("The Big Cheese", "Unknown company name")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I generated the following RQL from the Python client:

from 'Responses' where exists(user) and not user in ($p0)

Which was printed from:

with self.document_store.open_session() as session:
    query: DocumentQuery[dict[Any, Any]] = (
        session
        .query_collection("Responses")
        .not_()
        .where_in(field_name="user", values=("SL3789", "MB4557"))
    )
    print(query._to_string())

And in the python client, there is no way to generate the RQL you stated:

def where_in(self, field_name: str, values: Collection, exact: Optional[bool] = None) -> DocumentQuery[_T]:
    self._where_in(field_name, values, exact)
    return self

Since field_name is a required field. And then in the RQL generator, there is no option to enter the else condition from where_in since field_name is always required:

def __negate_if_needed(self, tokens: List[QueryToken], field_name: Optional[str]) -> None:
    if not self._negate:
        return
  
    self._negate = False
  
    if not tokens or isinstance(tokens[-1], OpenSubclauseToken):
        if field_name is not None:
            self._where_exists(field_name)
        else:
            self._where_true()
        self._and_also()
  
    tokens.append(NegateToken.instance())

I do agree with your example you gave in your comment, since in the case where the field user does not exist, I would also want to return documents. Should I submit a ticket in the python client repo for this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, no need, I wrote it down to check in all the Client APIs, thanks!

…lt set is different based on the provided condition
where true and not Name in ("The Big Cheese", "Unknown company name")
```
</TabItem>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting aside the separate issue of the Client API Not generating the where true clause in the produced RQL,
the documentation here should explain the actual RQL rule.

The following ContentFrame block should be used for the in operator:

<ContentFrame>

#### Operator: &nbsp;&nbsp; `in`

The `in` operator evaluates a field against a list of values.  
It will return results if the field matches **any** of the items in that list.    

<TabItem>
```csharp
from "Companies" 
where Name in ("The Big Cheese", "Unknown company name")
```
</TabItem>

<TabItem>
```csharp
from "Orders" 
where Lines[].ProductName in ("Chang", "Spegesild", "Unknown product name") 
```
</TabItem>
    
---

**To negate an `in` condition**, use the `NOT` operator.  
However, in RQL, `NOT` is not used as a standalone operator at the start of a `where` expression.  
Therefore, the negated condition must follow some **valid preceding expression**.  
For example:    
    
<TabItem>
```csharp
from "Companies" 
where true and NOT Name in ("The Big Cheese", "The Cracker Box")
```
</TabItem>
    
Instead of `where true`, any valid preceding expression can be used, even one that references a different field.  
For example:    
    
<TabItem>
```csharp
from "Companies" 
where exists(SomeFieldName) and NOT Name in ("The Big Cheese", "The Cracker Box")
```
</TabItem>      

</ContentFrame>

…should be more focused on explaining the actual RQL rule
@Danielle9897
Copy link
Copy Markdown
Member

Danielle9897 commented Mar 26, 2026

@slidwell44, please note:

  • @ppekrol has confirmed that exists(Name) (using the same field being negated)
    is the correct/preferred approach for negating an in condition.

  • Using where true or exists(SomeOtherField) as the preceding expression
    can produce unexpected results when some documents do not contain the negated field at all.

  • Therefore, suggesting the following for the "negate" part:

---

**To negate an `in` condition**, use the `NOT` operator.  
However, in RQL, `NOT` is not used as a standalone operator at the start of a `where` expression.  
Therefore, the negated condition must follow some **valid preceding expression**.  

To ensure correct results, use `exists(fieldName)` where `fieldName` is the field used in the `in` condition:
    
<TabItem>
```csharp
from "Companies" 
where exists(Name) and NOT Name in ("The Big Cheese", "The Cracker Box")
```
</TabItem>

Note: Using `where true` or `exists()` on a **different** field as the preceding expression may produce  
unexpected results when some documents do not contain the negated field.

</ContentFrame> 

This is now more concise and directly addresses the preferred pattern for negating the `IN` condition
@slidwell44
Copy link
Copy Markdown
Contributor Author

That makes sense to me.

When I tested out the other conditions in your note, I do see a use case for where true, however, it seems clever to implicitly return results that way. I believe it should be the intention of the developer to return documents that do not include the field_name being searched.

@ppekrol ppekrol merged commit 8388229 into ravendb:main Mar 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants