Learn MongoDB: Query Documents - II
Tags: mongodb, tutorial, database, nosql
Published: 2020-10-11 14:31:35

Continuing the [Query Documents - I](https://dev.to/paras594/learn-mongodb-query-documents-i-309a) post, let's complete the remaining operations. In previous post, I covered simple queries and querying embedded documents with several kinds of operators that are available in mongodb. In this post, operators related to arrays and evaluation of data are discussed. 

---

Table of Content: 

- [Evaluation Query Operators](#evaluation-query-operators)
- [Querying Arrays](#querying-arrays)
- [Array Query Operators](#array-operators)

---

**New Document Structure in pokemons collection:**

Instead of single weakness, now we will keep an array of weaknesses for a pokemon.

```json
{
   name: "pikachu",
   type: "Electric",
   stats: {
     health: 40,
     attack: 50,
     defense: 45
   },
   level: 16,
   weakness: ["ground", "grass", "dragon"], // now it's array
   evolution: "raichu",
   moves: [
      {name: "quick attack", dmg: 40},
      {name: "thunder bolt", dmg: 90},
      {name: "irontail", dmg: 50}
   ]   
}
```



## Evaluation Query Operators

There is nothing much to say about evaluation query operators. They just do evaluation.

- $regex (allows you to specify regex expression in your query)
- $text (useful when working with indexes in mongodb, therefore not covered now)
- $jsonSchema (For validating data against a schema)
- $expr
- $mod  ( { field: { $mod: [ divisor, remainder ] } })

Usage:

```bash
# $regex to find pokemons with "pi" in their name
> db.persons.find({ description: {$regex: /pi/}})

# create a validator when creating collection
# let's create a simple schema for pokemon collection
> db.createCollection( <collection>, { validator: { 
	required: ["name", "type", "level"],
   $jsonSchema: {
      name: { bsonType: "string" },
      type: { bsonType: "string" },
      level: { bsonType: "int", minimum: 1 }
   }
}})

# $mod operators helps you perform mod operation on a field against a number
# get all pokemons whose level are divisible by 5
> db.pokemons.find({level: {$mod: [5, 0]}}) # divisor, remainder
```



**$expr :** It is related to aggregation. It helps us to use aggregation expressions within the query.

> Note: There are some operations for which we need some knowledge of aggregation. Therefore, we will cover the relevant part for now and rest will be covered later.

- Comparing fields: You can use $expr operator to compare two fields. E.g. we can compare level and defense field in our pokemons collection (weird comparision, but will teach you about embedded field)

```bash
# get pokemons whose level are greater than their defense
> db.pokemons.find({$expr: {$gt: ["$level", "$stats.defense"] }})
```



>  As you can see, you need quotes and `$` sign when specifying the field in `$expr`
>
>  E.g. "$fieldName", "$fieldName.nestedFieldName"

There is another operator `$cond` that helps us in creating conditions (if, then, else). We will learn it later in the series.



## Querying Arrays

Arrays are here !! Now we will learn how to handle arrays inside documents. 

**Simple query for an element in array :** You can query arrays normally and mongo will take care of the rest. It will check if the value exists in array or not.

```bash
# find pokemons with weakness "ground"
> db.pokemons.find({weakness: "ground"})

# if you do something like this, it will check for exact match for array
> db.pokemons.find({weakness: ["ground"]})
```



**Querying an index in array :** It is possible to query for a specific index in array. Just specify the index similar to specifying a key in object.

```bash
> db.pokemons.find({"weakness.2": "electric" })
```



**What if we have embedded docs inside array?? (Hint: similar to embedded docs)**

```bash
# find pokemons who have "quick attack" move
> db.pokemons.find({"moves.name": "quick attack"})
```



This can get tricky when document structure gets more complicated. In our above example, we only looked for a single key. Let's see some more examples that can get us in trouble. We will use a different document structure instead of our pokemons one.

```json
// e.g collection = articles
{
   comments: [
      { name: "Nina", rating: 3 },
      { name: "Colt", rating: 4 },
      { name: "Rico", rating: 2.5}
   ]
}
```



```bash
# find articles where nina's has given rating, greater than 3

# this won't work, it will look for exact match
> db.articles.find({"comments": { name: "Nina", rating: {$gt: 2}}})

# this won't work either
# name can match different comment than the rating
> db.articles.find({"comments.name": "Nina", "comments.rating": {$gt: 2}})
```



We will solve this problem in later section, where we will learn about operators.



## Array Operators

Array operators are few but very useful. 

- Operators: `$all`, `$size`, `$elemMatch`



**$all :** To understand it, let's form a case.  Find all pokemons whose weaknesses are ground and electric.

```bash
> db.pokemons.find({weakness: {$all: ["ground", "electric"]}})

# Don't try the following query because 
# it will look for exact match + order 
> db.pokemons.find({weakness: ["ground", "electric"]})
```



`$all` makes sure it finds all elements in array. They can be objects, single values or arrays. It also ignores the order in which you specified elements in query.



**$size :** Simple...let's you query the size of array. 

```bash
# find pokemons with 4 moves
> db.pokemons.find({moves: {$size: 4}})
```



> $size operator only accepts exact number. Greater than or less than queries are not possible. 



**$elemMatch :** The operator we need is here !!!...Just kidding. Do you remember the unsolved mystery we just had when querying embedded documents in array ? `$elemMatch` can help us with that !! Let's see how

```json
// e.g collection = articles
{
   comments: [
      { name: "Nina", rating: 3 },
      { name: "Colt", rating: 4 },
      { name: "Rico", rating: 2.5}
   ]
}
```



```bash
# find articles where Nina has given a rating greater than 2
> db.articles.find({
   comments: {
      $elemMatch: {name: "Nina", rating: {$gt: 2}}
   }
})
```



What just happened in that query ?? 

`$elemMatch` helped us in defining how the document should look like, that can match our query.  Cool, isn't it ?

---

So, that was it for querying arrays and embedded docs. If you have any question, feel free to ask in comments. I will try my best to answer them. 

Hope you find this useful !

**Next Post :** [Update Documents](https://dev.to/paras594/learn-mongodb-update-documents-2mc3)

**Prev Post :** [Query Documents - Part I](https://dev.to/paras594/learn-mongodb-query-documents-i-309a)