eolas/Databases/MongoDB/Querying_a_collection.md

211 lines
5.6 KiB
Markdown
Raw Normal View History

2022-08-11 13:00:04 +01:00
---
tags:
- Databases
- 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
}
2022-08-12 08:30:04 +01:00
2022-08-11 13:00:04 +01:00
{
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.
2022-08-11 13:30:05 +01:00
## Return values with `find`
2022-08-11 13:00:04 +01:00
```js
async function getCourses(){
const courses = await Course.find()
console.log(courses)
}
```
2022-08-11 13:30:05 +01:00
## Filter values returned
This will return all the published courses where Tosh Gnomay is the author:
2022-08-11 13:00:04 +01:00
```js
async function getCourses(){
const courses = await Course.find({author: 'Tosh Gnomay', isPublished: true})
console.log(courses)
}
```
2022-08-11 13:30:05 +01:00
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.
2022-08-12 08:30:04 +01:00
## Querying with operators
2022-08-12 08:00:04 +01:00
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.
2022-08-11 13:30:05 +01:00
2022-08-12 08:00:04 +01:00
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
2022-08-11 13:30:05 +01:00
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 |
2022-08-11 14:00:04 +01:00
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:
2022-08-11 13:30:05 +01:00
```js
Course.find(({price: {$gte: 10, $lte: 20} }))
2022-08-11 14:00:04 +01:00
```
To filter course prices that are either 10, 15 or 20:
```js
Course.find(({price: {$in: [10, 15, 20] } }))
2022-08-12 08:00:04 +01:00
```
2022-08-12 08:30:04 +01:00
### 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)
}
```