Lesson 4
Logical Query Operators
Introduction

Hello there and welcome back! In the previous lessons, you were introduced to MongoDB query operators, which enable you to craft more complex queries. Specifically, you covered comparison operators like $gt, $gte, $eq, and others. In this lesson, we'll focus on logical query operators, which allow you to combine multiple conditions to fine-tune your data retrieval. Let's dive in!

Logical Query Operators

In MongoDB, logical query operators are used to filter data based on expressions that evaluate to true or false:

  • $and: Matches documents where all conditions are true.
  • $or: Matches documents where at least one condition is true.
  • $not: Matches documents where the condition is not true.
  • $nor: Matches documents where none of the conditions are true.
Understanding `$and` Operator

The $and operator combines multiple conditions and only matches documents where all conditions are met. Its syntax requires an array of objects, each representing a condition. Let's run the following command to find the comic books with genres including "Adventure" and featuring Spider-Man as one of the characters:

JavaScript
1use comic_book_store_db 2 3db.comic_books.find( 4 { $and: [ { genres: "Adventure" }, { "characters.name": "Spider-Man" } ] }, 5 { title: 1, genres: 1, _id: 0 } 6).pretty()

Looks a little bit bulky, right? Actually, the $and operator is the default in a MongoDB filter object, so you can omit it to simplify the expression, like so:

JavaScript
1use comic_book_store_db 2 3db.comic_books.find( 4 { genres: "Adventure", "characters.name": "Spider-Man" }, 5 { title: 1, genres: 1, _id: 0 } 6).pretty()

So why do we need the $and operator at all? Let's imagine we want to use the same field for querying. For example, suppose we want to find comic books that contain both "Sci-Fi" and "Mystic" genres:

JavaScript
1use comic_book_store_db 2 3db.comic_books.find( 4 { genres: "Sci-Fi", genres: "Mystic" }, 5 { title: 1, genres: 1, _id: 0 } 6).pretty()

This query will give you the wrong result because JSON objects don't allow duplicate fields; it will simply override the earlier value with the latter value. In this specific example, { genres: "Sci-Fi", genres: "Mystic" } will be equivalent to { genres: "Mystic" }. This is where the $and operator comes to the rescue:

JavaScript
1use comic_book_store_db 2 3db.comic_books.find( 4 { $and: [ { genres: "Sci-Fi" }, { genres: "Mystic" } ] }, 5 { title: 1, genres: 1, _id: 0 } 6).pretty()

This query will correctly find all comic books that belong to both Sci-Fi and Mystic genres. There are no such comics in our collection, by the way.

Understanding `$or` Operator

The $or operator retrieves documents where at least one of the specified conditions is true. To illustrate, let's use the $or operator to find comic books that are either very old (published before 1970) or very new (published after 2000). Here’s the query:

JavaScript
1use comic_book_store_db 2 3db.comic_books.find( 4 { $or: [ { published_year: { $lt: 1970 } }, { published_year: { $gt: 2000 } } ] }, 5 { title: 1, published_year: 1, _id: 0 } 6).pretty()

As you can see, its syntax is similar to the $and operator, requiring an array of objects, each representing a condition.

Understanding `$nor` Operator

The $nor operator is just the opposite of the $or operator, it retrieves documents where none of the conditions are true. In essence, they retrieve different parts of the collection based on the specified conditions. Let's replace the $or operator with $nor in the following code snippet, like so:

mongo
1use comic_book_store_db 2 3db.comic_books.find( 4 { $nor: [ { published_year: { $lt: 1970 } }, { published_year: { $gt: 2000 } } ] }, 5 { title: 1, published_year: 1, _id: 0 } 6).pretty()

It will simply retrieve us all the comic books which are neither old, nor new and were published between 1970 and 2000.

Understanding `$not` Operator

Last but not least, the $not operator! The $not operator matches documents where the condition is not true. If we want to find a comic book in our comic_book_store_db that was not written by Jack Kirby, we would use:

JavaScript
1use comic_book_store_db 2 3db.comic_books.findOne( 4 { "writer.name": {$not: {$eq: "Jack Kirby"} } }, 5 { title: 1, "writer.name": 1, _id: 0 } 6)

There are a few important syntax considerations with the $not operator. Firstly, it shouldn't be at the top level of the query like this:

  • Incorrect: { $not: { genres: "Horror" } }
  • Fixed: { genres: { $not: { $eq: "Horror" } } }

Additionally, its value should always be an object:

  • Incorrect: { published_year: { $not: 1995 } }
  • Fixed: { published_year: { $not: { $eq: 1995 } } }

So be mindful of the syntax.

Summary

Great job on making it through this lesson! Today, we explored logical query operators in MongoDB and used $and, $or, $not, and $nor to refine our data retrieval. Keep practicing using these operators until they become second nature. Our next steps? Applying these concepts in the practice exercises that follow this lesson.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.