207 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
---
 | 
						|
categories:
 | 
						|
  - Databases
 | 
						|
tags: [mongo-db, node-js, mongoose]
 | 
						|
---
 | 
						|
 | 
						|
# 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](/Databases/MongoDB/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](/Logic/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);
 | 
						|
}
 | 
						|
```
 |