# Logical Operators

## Overview

Logical operators allow you to match documents based on the **boolean result** :white\_check\_mark: :x: coming from a set of expressions. The logical expressions are evaluated for each document in your filter and if their boolean result matches the expected one *(true or false)* are included or excluded respectively in the returned result. The section contains samples for the following operators:

| Operator | Description                                                        |
| -------- | ------------------------------------------------------------------ |
| **AND**  | Matches documents that fulfill all specified conditions            |
| **NOT**  | Matches documents that don't fulfill the specified expression      |
| **OR**   | Matches documents that fulfill at least one of a set of conditions |
| **NOR**  | Matches documents that fail to fulfill both conditions             |

![Logical operators](https://2076499567-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1LyPqYq4CEFXnjdYHF%2F-M4hpEl4yvQAgwQ6lneO%2F-M4it3xJDU8_xXdHiXx-%2Flogical.png?alt=media\&token=cf7cc7f7-b2d2-4056-b696-4940f06dae44)

## *AND* operator - *$and*

The AND *operator* performs a logical AND on a set of expressions and match documents that satisfy all of them.&#x20;

{% tabs %}
{% tab title="Syntax" %}

```csharp
Builders<T>.Filter
    .And(FilterDefinition<T>[] filters)
```

{% endtab %}
{% endtabs %}

Create as many **filter definitions** you want and pass them as an argument to the **`And`** `FilterDefinitionBuilder` method.&#x20;

The sample uses an *And* operator to find all documents that have male *gender* **AND** have the *profession* field equal to "*Doctor*".

{% tabs %}
{% tab title="C#" %}
{% code title="LogicalOperators.cs" %}

```csharp
var collection = database
    .GetCollection<User>(Constants.UsersCollection);

// create an equality filter on the gender for 'male' (0)
var maleFilter = Builders<User>.Filter
    .Eq(u => u.Gender, Gender.Male);
    
// create an equality filter on profession for 'Doctor'
var doctorFilter = Builders<User>.Filter
    .Eq(u => u.Profession, "Doctor");
    
// compine the filters with AND operator
var maleDoctorsFilter = Builders<User>.Filter
    .And(maleFilter, doctorFilter);

var maleDoctors = await collection.Find(maleDoctorsFilter).ToListAsync();
```

{% endcode %}
{% endtab %}

{% tab title="Bson" %}

```csharp
var bsonCollection = database
    .GetCollection<BsonDocument>(Constants.UsersCollection);

var bsonMaleFilter = Builders<BsonDocument>.Filter
    .Eq("gender", Gender.Male);
    
var bsonDoctorFilter = Builders<BsonDocument>.Filter
    .Eq("profession", "Doctor");
    
var bsonMaleDoctorsFilter = Builders<BsonDocument>.Filter
    .And(bsonMaleFilter, bsonDoctorFilter);
    
var bsonMaleDoctors = await bsonCollection
    .Find(bsonMaleDoctorsFilter).ToListAsync();
```

{% endtab %}

{% tab title="Shell" %}

```javascript
db.users.find({ $and: [
    { profession: { $eq: "Doctor"} }, 
    {gender: { $eq: 0} }
]})

--------------------------- 
        
// sample matched document
{
	"_id" : ObjectId("5e91e3ba3c1ba62570a67bdd"),
	"gender" : 0, // matched here
	"firstName" : "Ralph",
	"lastName" : "Emard",
	"userName" : "Ralph78",
	"avatar" : "https://s3.amazonaws.com/uifaces/faces/twitter/xripunov/128.jpg",
	"email" : "Ralph62@yahoo.com",
	"dateOfBirth" : ISODate("1967-02-18T00:07:22.546+02:00"),
	"address" : {
		"street" : "3046 Orn Locks",
		"suite" : "Apt. 046",
		"city" : "North Nestorview",
		"state" : "Wyoming",
		"zipCode" : "03620-0321",
		"geo" : {
			"lat" : 54.3724,
			"lng" : 127.4216
		}
	},
	"phone" : "422-441-7773",
	"website" : "neva.name",
	"company" : {
		"name" : "Kilback LLC",
		"catchPhrase" : "Configurable 6th generation encoding",
		"bs" : "transition seamless initiatives"
	},
	"salary" : 4787,
	"monthlyExpenses" : 4546,
	"favoriteSports" : [
		"Darts",
		"American Football",
		"Basketball",
		"Cricket",
		"Boxing",
		"Golf",
		"Beach Volleyball",
		"Ice Hockey",
		"Water Polo",
		"Table Tennis",
		"Tennis",
		"Snooker",
		"Cycling",
		"MMA",
		"Handball"
	],
	"profession" : "Doctor" // matched here
}
```

{% endtab %}

{% tab title="User" %}

```csharp
public class User
{
    [BsonId]
    [BsonIgnoreIfDefault] // required for replace documents 
    public ObjectId Id { get; set; }
    public Gender Gender { get; set; }
    public string FirstName {get; set; }
    public string LastName {get; set; }
    public string UserName {get; set; }
    public string Avatar {get; set; }
    public string Email {get; set; }
    public DateTime DateOfBirth {get; set; }
    public AddressCard Address {get; set; }
    public string Phone {get; set; }
    
    [BsonIgnoreIfDefault]
    public string Website {get; set; }
    public CompanyCard Company {get; set; }
    public decimal Salary { get; set; }
    public int MonthlyExpenses { get; set; }
    public List<string> FavoriteSports { get; set; }
    public string Profession { get; set; }
}
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
The *Gender* property on the `User` class is an `Enum` type and the driver is smart enough :man\_mage: :owl: to translate it properly when sending the query to MongoDB
{% endhint %}

You can combine as many filters as you want to an AND operator. The following sample finds all documents that match the following criteria:

1. They have gender *Female* :woman\_health\_worker:&#x20;
2. They are either *"Teacher", Nurse" or "Dentist"*  :school: :hospital:&#x20;
3. Their salary is between 2000 AND 3200 :moneybag:&#x20;

{% tabs %}
{% tab title="C#" %}
{% code title="LogicalOperators.cs" %}

```csharp
var collection = database.GetCollection<User>(Constants.UsersCollection);

// female filter - condition 1
var femaleFilter = Builders<User>.Filter.Eq(u => u.Gender, Gender.Female);

// profession filter - condition 2
var teacherOrNurseFilter = Builders<User>.Filter
  .In(u => u.Profession, new[] { "Teacher", "Nurse", "Dentist" });
    
// salary filter - condition 3
var salaryFilter = Builders<User>.Filter.And(
                Builders<User>.Filter.Gte(u => u.Salary, 2000),
                Builders<User>.Filter.Lte(u => u.Salary, 3200));

// combined filter
var combinedFilter = Builders<User>.Filter
                .And(femaleFilter, teacherOrNurseFilter, salaryFilter);
    
var matchedUsers = await collection.Find(combinedFilter).ToListAsync();
```

{% endcode %}
{% endtab %}

{% tab title="Bson" %}

```csharp
var bsonCollection = database
    .GetCollection<BsonDocument>(Constants.UsersCollection);

// female filter - condition 1
var bsonFemaleFilter = Builders<BsonDocument>.Filter
    .Eq("gender", Gender.Female);

// profession filter - condition 2
var bsonTeacherOrNurseFilter = Builders<BsonDocument>.Filter
    .In("profession", new[] { "Teacher", "Nurse", "Dentist" });
    
// salary filter - condition 3
var bsonSalaryFilter = Builders<BsonDocument>.Filter.And(
    Builders<BsonDocument>.Filter.Gte("salary", 2000),
    Builders<BsonDocument>.Filter.Lte("salary", 3200)
);

// combined filter
var bsonCombinedFilter = Builders<BsonDocument>.Filter
    .And(bsonFemaleFilter, bsonTeacherOrNurseFilter, bsonSalaryFilter);
    
var bsonMatchedUsers = await bsonCollection
    .Find(bsonCombinedFilter).ToListAsync();
```

{% endtab %}

{% tab title="Shell" %}

```javascript
db.users.find( 
{ $and: [
             { "gender" : 1 },
             { profession: { $in: ["Teacher", "Nurse", "Dentist"]}},
             { $and : [ 
                         { salary: { $gte: 2000 } }, 
                         { salary: { $lte: 3200 }} 
             ] } 
        ]})
        
---------------------------  
     
// sample matched document
{
	"_id" : ObjectId("5e9335512013741d0cb64570"),
	"gender" : 1, // matched here
	"firstName" : "Silvia",
	"lastName" : "Rice",
	"userName" : "Silvia6",
	"avatar" : "https://s3.amazonaws.com/uifaces/faces/twitter/solid_color/128.jpg",
	"email" : "Silvia_Rice86@hotmail.com",
	"dateOfBirth" : ISODate("1999-05-20T05:09:46.133+03:00"),
	"address" : {
		"street" : "53815 Flo Creek",
		"suite" : "Apt. 845",
		"city" : "Gibsonburgh",
		"state" : "Vermont",
		"zipCode" : "90988",
		"geo" : {
			"lat" : -11.4545,
			"lng" : 87.8866
		}
	},
	"phone" : "(389) 267-5524",
	"company" : {
		"name" : "Klein, Jacobi and Cormier",
		"catchPhrase" : "Open-architected methodical alliance",
		"bs" : "implement dynamic e-markets"
	},
	"salary" : 2935, // matched here
	"monthlyExpenses" : 3826,
	"favoriteSports" : [
		"Darts",
		"Table Tennis",
		"Baseball",
		"Volleyball",
		"Basketball",
		"Snooker",
		"Tennis",
		"Moto GP",
		"Motor Sport",
		"Boxing",
		"Water Polo",
		"Handball",
		"MMA",
		"Soccer",
		"Cycling"
	],
	"profession" : "Dentist" // matched here
}
```

{% endtab %}

{% tab title="User" %}

```csharp
public class User
{
    [BsonId]
    [BsonIgnoreIfDefault] // required for replace documents 
    public ObjectId Id { get; set; }
    public Gender Gender { get; set; }
    public string FirstName {get; set; }
    public string LastName {get; set; }
    public string UserName {get; set; }
    public string Avatar {get; set; }
    public string Email {get; set; }
    public DateTime DateOfBirth {get; set; }
    public AddressCard Address {get; set; }
    public string Phone {get; set; }
    
    [BsonIgnoreIfDefault]
    public string Website {get; set; }
    public CompanyCard Company {get; set; }
    public decimal Salary { get; set; }
    public int MonthlyExpenses { get; set; }
    public List<string> FavoriteSports { get; set; }
    public string Profession { get; set; }
}
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
The inner filter definitions passed as arguments in the **`And`** method can be as complex as you want to.
{% endhint %}

## *NOT* operator - *$ne*

The NOT *operator* performs a logical NOT on an expression and match documents that **don't satisfy** the expression.&#x20;

{% tabs %}
{% tab title="Syntax" %}

```csharp
Builders<T>.Filter
    .Not(FilterDefinition<T> filter)
```

{% endtab %}
{% endtabs %}

Create a **filter definition** and pass it as an argument to the **`Not`** `FilterDefinitionBuilder` method. The boolean expression's result for the matched documents will be **false**, meaning that they don't satisfy the expression.

The sample uses an *Not* operator to find all documents having male *gender,* which can be translated as **NOT** *female*.

{% tabs %}
{% tab title="C#" %}
{% code title="LogicalOperators.cs" %}

```csharp
var collection = database
    .GetCollection<User>(Constants.UsersCollection);

// Negates the internal equality filter
var notMaleFilter = Builders<User>.Filter.Not(
    // equality filter on gender for Male
    Builders<User>.Filter.Eq(u => u.Gender, Gender.Male)
);

var femaleUsers = await collection.Find(notMaleFilter).ToListAsync();
```

{% endcode %}
{% endtab %}

{% tab title="Bson" %}

```csharp
var bsonCollection = database
    .GetCollection<BsonDocument>(Constants.UsersCollection);

var bsonNotMaleFilter = Builders<BsonDocument>.Filter
.Not(
    Builders<BsonDocument>.Filter.Eq("gender", Gender.Male)
);

var bsonFemaleUsers = await bsonCollection
    .Find(bsonNotMaleFilter).ToListAsync();
```

{% endtab %}

{% tab title="Shell" %}

```javascript
db.users.find( { gender: { $ne: 0 }})

--------------------------- 

// sample matched document
{
	"_id" : ObjectId("5e9335512013741d0cb64552"),
	"gender" : 1, //matched here
	"firstName" : "Rosie",
	"lastName" : "Okuneva",
	"userName" : "Rosie55",
	"avatar" : "https://s3.amazonaws.com/uifaces/faces/twitter/joe_black/128.jpg",
	"email" : "Rosie6@gmail.com",
	"dateOfBirth" : ISODate("1984-11-29T12:38:37.812+02:00"),
	"address" : {
		"street" : "5668 Sonya Fords",
		"suite" : "Apt. 584",
		"city" : "North Birdieside",
		"state" : "New Jersey",
		"zipCode" : "46111",
		"geo" : {
			"lat" : 50.373,
			"lng" : 175.2369
		}
	},
	"phone" : "867.783.1346 x7152",
	"website" : "ola.biz",
	"company" : {
		"name" : "Schaefer, Lang and Considine",
		"catchPhrase" : "User-friendly regional product",
		"bs" : "incubate mission-critical technologies"
	},
	"salary" : 4409,
	"monthlyExpenses" : 6018,
	"favoriteSports" : [
		"Beach Volleyball",
		"Golf",
		"Soccer",
		"Volleyball",
		"Moto GP",
		"Darts",
		"American Football",
		"Basketball",
		"Snooker",
		"MMA",
		"Motor Sport"
	],
	"profession" : "Visual Designer"
}
```

{% endtab %}

{% tab title="User" %}

```csharp
public class User
{
    [BsonId]
    [BsonIgnoreIfDefault] // required for replace documents 
    public ObjectId Id { get; set; }
    public Gender Gender { get; set; }
    public string FirstName {get; set; }
    public string LastName {get; set; }
    public string UserName {get; set; }
    public string Avatar {get; set; }
    public string Email {get; set; }
    public DateTime DateOfBirth {get; set; }
    public AddressCard Address {get; set; }
    public string Phone {get; set; }
    
    [BsonIgnoreIfDefault]
    public string Website {get; set; }
    public CompanyCard Company {get; set; }
    public decimal Salary { get; set; }
    public int MonthlyExpenses { get; set; }
    public List<string> FavoriteSports { get; set; }
    public string Profession { get; set; }
}
```

{% endtab %}
{% endtabs %}

## *OR* operator - *$or*

The *OR* operator performs a logical OR on an **set of expressions** and matches documents that **satisfy** at least on of the expressions.&#x20;

{% tabs %}
{% tab title="Syntax" %}

```csharp
Builders<T>.Filter.Or(FilterDefinition<T>[] filters)
```

{% endtab %}
{% endtabs %}

Create as many **filter definitions** you want and pass them as an argument to the **`Or`** `FilterDefinitionBuilder` method. The filters passed as parameters can be as complex as you want.

The sample uses an *Or* operator to find all documents having *salary,* either too low *(less than 1500)* or too high *( greater than 4000).*

{% tabs %}
{% tab title="C#" %}
{% code title="LogicalOperators.cs" %}

```csharp
var collection = database.GetCollection<User>(Constants.UsersCollection);

// users with salary either < 1500 (too low) or > 4000 (too high)
var orSalaryFilter = Builders<User>.Filter.Or(
    Builders<User>.Filter.Lt(u => u.Salary, 1500), // 1st expression
    Builders<User>.Filter.Gt(u => u.Salary, 4000)  // 2nd expression
);

var lowOrHighSalaryUsers = await collection
    .Find(orSalaryFilter).ToListAsync();
```

{% endcode %}
{% endtab %}

{% tab title="Bson" %}

```csharp
var bsonCollection = database
    .GetCollection<BsonDocument>(Constants.UsersCollection);

var bsonOrSalaryFilter = Builders<BsonDocument>.Filter.Or(
    Builders<BsonDocument>.Filter.Lt("salary", 1500),
    Builders<BsonDocument>.Filter.Gt("salary", 4000)
);

var bsonLowOrHighSalaryUsers = await bsonCollection
    .Find(bsonOrSalaryFilter).ToListAsync();
```

{% endtab %}

{% tab title="Shell" %}

```javascript
db.users.find( { $or: [ 
    { salary: { $lt: 1500 } }, 
    { salary: { $gt: 4000 }}
]})

-------------------------

// sample matched document
{
	"_id" : ObjectId("5e9335512013741d0cb6454a"),
	"gender" : 0,
	"firstName" : "Carlton",
	"lastName" : "Bergstrom",
	"userName" : "Carlton_Bergstrom",
	"avatar" : "https://s3.amazonaws.com/uifaces/faces/twitter/joe_black/128.jpg",
	"email" : "Carlton28@yahoo.com",
	"dateOfBirth" : ISODate("1952-09-18T11:22:04.592+03:00"),
	"address" : {
		"street" : "0021 Sheila Corners",
		"suite" : "Apt. 199",
		"city" : "Schmidtfort",
		"state" : "Rhode Island",
		"zipCode" : "09682",
		"geo" : {
			"lat" : 11.8535,
			"lng" : 102.024
		}
	},
	"phone" : "1-300-468-9739 x188",
	"website" : "weldon.name",
	"company" : {
		"name" : "Dooley, Schmitt and Wiegand",
		"catchPhrase" : "Robust coherent migration",
		"bs" : "empower front-end vortals"
	},
	"salary" : 4005, // matched here (too high)
	"monthlyExpenses" : 3483,
	"favoriteSports" : [
		"Formula 1",
		"Volleyball"
	],
	"profession" : "Personal Trainer"
}
```

{% endtab %}

{% tab title="User" %}

```csharp
public class User
{
    [BsonId]
    [BsonIgnoreIfDefault] // required for replace documents 
    public ObjectId Id { get; set; }
    public Gender Gender { get; set; }
    public string FirstName {get; set; }
    public string LastName {get; set; }
    public string UserName {get; set; }
    public string Avatar {get; set; }
    public string Email {get; set; }
    public DateTime DateOfBirth {get; set; }
    public AddressCard Address {get; set; }
    public string Phone {get; set; }
    
    [BsonIgnoreIfDefault]
    public string Website {get; set; }
    public CompanyCard Company {get; set; }
    public decimal Salary { get; set; }
    public int MonthlyExpenses { get; set; }
    public List<string> FavoriteSports { get; set; }
    public string Profession { get; set; }
}
```

{% endtab %}
{% endtabs %}

## *NOR* operator - *$nor*

The *NOR* operator performs a logical NOR on an **set of expressions** and matches documents that **fail to satisfy** all the expressions. Despite the fact that MongoDB supports the [$nor](https://docs.mongodb.com/manual/reference/operator/query/nor/) operator, you won't find any method on the C# driver. That's totally fine though because you can built it using the AND operator and negating the internal filters.&#x20;

Create as many filter definitions you want **to fail** and pass them as an argument to the **`And`** `FilterDefinitionBuilder` method. The filters passed as parameters can be as complex as you want.

The sample finds documents that **fail** to satisfy the following criteria:

1. Have *profession* equal to "Doctor"
2. Have *salary* less than 4500

Since the matched documents needs to fail the above criteria, you should use their negates with an AND operator.

{% tabs %}
{% tab title="C#" %}
{% code title="LogicalOperators.cs" %}

```csharp
var collection = database
    .GetCollection<User>(Constants.UsersCollection);

var norFilter = Builders<User>.Filter.And(
    Builders<User>.Filter // negate 1st filter
        .Not(Builders<User>.Filter.Eq(u => u.Profession, "Doctor")),    
    Builders<User>.Filter // negate 2nd filter
        .Not(Builders<User>.Filter.Lt(u => u.Salary, 4500))
);

var norUsers = await collection
    .Find(norFilter).ToListAsync();
```

{% endcode %}
{% endtab %}

{% tab title="Bson" %}

```csharp
var bsonCollection = database
    .GetCollection<BsonDocument>(Constants.UsersCollection);

var bsonNorFilter = Builders<BsonDocument>.Filter.And(
    Builders<BsonDocument>.Filter
        .Not(Builders<BsonDocument>.Filter.Eq("profession", "Doctor")),
    Builders<BsonDocument>.Filter
        .Not(Builders<BsonDocument>.Filter.Lt("salary", 4500)));

var bsonNorUsers = await bsonCollection
    .Find(bsonNorFilter).ToListAsync();
```

{% endtab %}

{% tab title="Shell" %}

```javascript
db.users.find(
{ $nor: [ { profession: { $eq: "Doctor" } }, 
          { salary: { $lt: 4500 }}
        ]})
        
----------------------

// sample matched document
{
	"_id" : ObjectId("5e9335512013741d0cb6454e"),
	"gender" : 0,
	"firstName" : "Richard",
	"lastName" : "Hirthe",
	"userName" : "Richard.Hirthe52",
	"avatar" : "https://s3.amazonaws.com/uifaces/faces/twitter/ruzinav/128.jpg",
	"email" : "Richard_Hirthe@gmail.com",
	"dateOfBirth" : ISODate("1999-09-11T11:24:04.010+03:00"),
	"address" : {
		"street" : "785 Adams Dale",
		"suite" : "Suite 379",
		"city" : "Labadiestad",
		"state" : "Texas",
		"zipCode" : "45075",
		"geo" : {
			"lat" : 34.7933,
			"lng" : 70.5508
		}
	},
	"phone" : "977.924.7118",
	"website" : "charlie.net",
	"company" : {
		"name" : "O'Keefe LLC",
		"catchPhrase" : "Triple-buffered maximized database",
		"bs" : "synergize next-generation architectures"
	},
	"salary" : 4603, // matched here
	"monthlyExpenses" : 3355,
	"favoriteSports" : [
		"Snooker",
		"Water Polo",
		"Table Tennis",
		"Ice Hockey",
		"Volleyball",
		"Soccer",
		"Handball",
		"American Football",
		"Golf",
		"Boxing",
		"Beach Volleyball",
		"Formula 1",
		"Tennis",
		"Motor Sport",
		"Baseball"
	],
	"profession" : "Lawyer" // matched here
}
```

{% endtab %}

{% tab title="User" %}

```csharp
public class User
{
    [BsonId]
    [BsonIgnoreIfDefault] // required for replace documents 
    public ObjectId Id { get; set; }
    public Gender Gender { get; set; }
    public string FirstName {get; set; }
    public string LastName {get; set; }
    public string UserName {get; set; }
    public string Avatar {get; set; }
    public string Email {get; set; }
    public DateTime DateOfBirth {get; set; }
    public AddressCard Address {get; set; }
    public string Phone {get; set; }
    
    [BsonIgnoreIfDefault]
    public string Website {get; set; }
    public CompanyCard Company {get; set; }
    public decimal Salary { get; set; }
    public int MonthlyExpenses { get; set; }
    public List<string> FavoriteSports { get; set; }
    public string Profession { get; set; }
}
```

{% endtab %}
{% endtabs %}

:bulb: Of course you can build a simple extension method that does this for you and makes things a little bit easier.

{% tabs %}
{% tab title="C#" %}

```csharp
var collection = database.GetCollection<User>(Constants.UsersCollection);

var firstFilterToFail = Builders<User>.Filter
    .Eq(u => u.Profession, "Doctor");
    
var secondFilterToFail = Builders<User>.Filter
    .Lt(u => u.Salary, 4500);
    
var extensionNorFilter = Builders<User>.Filter
    .Nor(firstFilterToFail, secondFilterToFail);
```

{% endtab %}

{% tab title="Extensions" %}
{% code title="Extensions.cs" %}

```csharp
public static FilterDefinition<T> Nor<T>(
    this FilterDefinitionBuilder<T> builder, 
    params FilterDefinition<T>[] filters)
{
    return builder.And(
        filters.Select(builder.Not)
    );
}
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://chsakell.gitbook.io/mongodb-csharp-docs/crud-basics/read-documents/logical-operators.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
