---
tags:
  - mongo-db
  - node-js
  - mongoose
  - databases
---

# Query a Mongo collection with Mongoose

We now have the following entries in our `courses` collection:

```js
{
  name: 'Python Course',
  author: 'Terry Ogleton',
  tags: [ 'python', 'backend' ],
  isPublished: true,
  _id: new ObjectId("62f4e2527ac4aa2c30d41d23"),
  date: 2022-08-11T11:04:50.750Z,
  __v: 0
}

{
  name: 'Javascript Course',
  author: 'Tosh Gnomay',
  tags: [ 'js', 'frontend' ],
  isPublished: true,
  _id: new ObjectId("62f4e2527ac4aa2c30d41d24"),
  date: 2022-08-11T11:04:50.750Z,
  __v: 0
}

```

Now we will query the collection. This capability is provided via the Mongoose
schema class we used to create the `Course`
[model](Create_collections_and_documents_with_Mongoose.md#models).
We have the following methods available to use from the schema:

- `find`
- `findById`
- `findByIdAndRemove`
- `findByIdAndUpdate`
- `findOne`
- `findOneAndUpdate`
- `findOneAndRemove`
- ...

The various `find` methods return a value that is promisified.

## Return values with `find`

```js
async function getCourses() {
  const courses = await Course.find();
  console.log(courses);
}
```

## Filter values returned

This will return all the published courses where Tosh Gnomay is the author:

```js
async function getCourses() {
  const courses = await Course.find({
    author: "Tosh Gnomay",
    isPublished: true,
  });
  console.log(courses);
}
```

This time we will filter by the same author but we will add additional
parameters to distinguish:

- only the first ten entries (using `.limit(10)`)
- sort ascending by name (using `.sort({name: 1}))` , to descend we would use
  `-1`)
- only return the properties `name` and `tags` for the item in the collection
  (using `.select({name: 1, tags: 1})`)

```js
async function getCourses() {
  const courses = await Course.find({
    author: "Tosh Gnomay",
    isPublished: true,
  })
    .limit(10)
    .sort({ name: 1 })
    .select({ name: 1, tags: 1 });
  console.log(courses);
}
```

This returns:

```js
[
  {
    _id: new ObjectId("62f4f07a875cff48827b8731"),
    name: "Java Course",
    tags: ["java", "backend"],
  },
  {
    _id: new ObjectId("62f4e2527ac4aa2c30d41d24"),
    name: "Javascript Course",
    tags: ["js", "frontend"],
  },
];
```

> Note that the UUID is always returned, whether we specify it or not.

## Querying with operators

So far when filtering we have been doing so with reference to properties that
exist on the document's model (`author`, `isPublished` etc) and we have applied
tranformations on the data returned (sorting, limiting the number or matches
etc.). However we can also apply **operators** within our queries. Operators
allow us to perform computations on the data, for example: for a given numerical
property on an object, return the objects for which this value is within a
certain range.

When we apply operators we use the `$` symbol before the operator and pass the
operator function as an object.

The schema:

```
Model.find( { property: { $operator: conditions } } )
```

### Comparison operators

The following comparison operators are available in MongoDB:

| Operator | Function                  |
| -------- | ------------------------- |
| `eq`     | Equal to                  |
| `ne`     | Not equal to              |
| `gt`     | Greater than              |
| `gte`    | Greater than or less than |
| `lt`     | Less than                 |
| `lte`    | Less than or equal to     |
| `in`     | In                        |
| `nin`    | Not in                    |

We can employ these comparators within a `.find` filter. For example let's
imagine that our `courses` instances have a property of `price`.

To filter course prices that are greater than or equal to 10 and less than or
equal to 29:

```js
Course.find({ price: { $gte: 10, $lte: 20 } });
```

To filter course prices that are either 10, 15 or 20:

```js
Course.find({ price: { $in: [10, 15, 20] } });
```

### Logical operators

When we apply logical operators, we do not apply the query within the main
`find` method. We use a dedicated method that corresponds to the logical
predicate.

For example to query by logical
[OR](Truth-functional_connectives.md#disjunction):

```js
async function getCourses() {
  const courses = await Course.find().or([
    { author: "Tosh Gnomay" },
    { isPublished: true },
  ]);
  console.log(courses);
}
```

We write each disjunct as an object representing the conditions we are filtering
for within an array that is passed to the `.or()` method.

The same syntax applies for conjunction.

### Regular expressions

When filtering by strings we can use Regex for greater power.

Previously we filtered by the author name:

```js
.find({author: "Tosh Gnomay"})
```

To demonstrate regex we could filter by names beginning with `T`:

```js
.find({author: /^T*/})
```

```js
async function getCourses() {
  const courses = await Course.find()
    .or([{ author: "Tosh Gnomay" }, { isPublished: true }])
    .count();
  console.log(courses);
}
```

This will return a number.

### Pagination

We previously used the `limit()` method to control how many matches we return
from a query. We can extend this functionality by creating pagination. This
allows us to meter the return values into set chunks. This is used frequently
when interacting with a database through a mediating RESTful API. For example to
return values from endpoints such as:

```
/api/courses?pageNumber=2&pageSize=10
```

To do this you pass two values as query parameters

```js
const pageNumber = 2;
const pageSize = 10;

async function getCourses() {
  const courses = await Course.find()
    .skip(pageNumber - 1 * pageSize)
    .limit(pageSize);
  console.log(courses);
}
```
