-
-
Install & Set up mongoose -
Add
mongodb
andmongoose
to the project'spackage.json
. Then requiremongoose
. Store your mLab database URI in the private.env
file asMONGO-URI
. Connect to the database usingmongoose.connect(<Your URI>)
const mongoose - require('mongoose'); mongoose.connect(process.env.MONGO-URI, { useNewUrlParser: true });
-
-
-
Create a 'Person' Model -
-
First of all we need a Schema. Each schema maps to a MongoDB collection and defines the shape of the documents within that collection. Schemas are building block for Models. They can be nested to create complex models, but in this case we'll keep things simple. A model allows you to create instances of your objects, called documents.
-
Create a person having this prototype :
- Person Prototype - name : string [required] age : number favoriteFoods : array of strings ()
-
Use the mongoose basic -schema types-. If you want you can also add more fields, use simple validators like
required
orunique
, and setdefault
values. See the mongoose docs. -
Note: Glitch is a real server, and in real servers interactions with the db are placed in handler functions, to be called when some event happens (e.g. someone hits an endpoint on your API). We'll follow the same approach in these exercises. The
done()
function is a callback that tells us that we can proceed after completing an asynchronous operation such as inserting, searching, updating or deleting. It's following the Node convention and should be called asdone(null, data)
on success, ordone(err)
on error. Warning - When interacting with remote services, errors may occur !``` - Example - var someFunc - function(done) { ... do something (risky) ... if(error) return done(error); done(null, result); }; ```
-
-
-
-
Create and Save a Person -
-
Create a
document
instance using thePerson
constructor you build before. Pass to the constructor an object having the fieldsname
,age
, andfavoriteFoods
. Their types must be conformant to the ones in the PersonSchema
. Then call the methoddocument.save()
on the returned document instance, passing to it a callback using the Node convention. This is a common pattern, all the CRUD methods take a callback function like this as the last argument.- Example - ... person.save(function(err, data) { ...do your stuff here... });
-
- Create many People with
Model.create()
-
- Create many People with
-
-
Sometimes you need to create many Instances of your Models,
e.g. when seeding a database with initial data. Model.create()
takes an array of objects like [{name: 'John', ...}, {...}, ...],
as the 1st argument, and saves them all in the db.
Create many people using Model.create()
, using the function argument
'arrayOfPeople'.
-
- Use
Model.find()
-
- Use
Find all the people having a given name, using Model.find() -> [Person]
In its simplest usage, Model.find()
accepts a query document (a JSON
object ) as the first argument, and returns an array of matches.
It supports an extremely wide range of search options. Check it in the docs.
Use the function argument personName
as search key.
-
- Use
Model.findOne()
-
- Use
Model.findOne()
behaves like .find()
, but it returns only one
document, even if there are more. It is especially useful
when searching by properties that you have declared as unique.
Find just one person which has a certain food in her favorites,
using Model.findOne() -> Person
. Use the function
argument food
as search key
-
- Use
Model.findById()
-
- Use
When saving a document, mongodb automatically add the field -id
,
and set it to a unique alphanumeric key. Searching by -id
is an
extremely frequent operation, so moongose
provides a dedicated
method for it. Find the (only!!) person having a certain Id,
using Model.findById() -> Person
.
Use the function argument 'personId' as search key.
-
- Classic Update : Find, Edit then Save -
In the good old days this was what you needed to do if you wanted to edit
a document and be able to use it somehow e.g. sending it back in a server
response. Mongoose has a dedicated updating method : Model.update()
,
which is directly binded to the low-level mongo driver.
It can bulk edit many documents matching certain criteria, but it doesn't
pass the edited document to its callback, only a 'status' message.
Furthermore it makes validation difficult, because it just
direcly calls the mongodb driver.
Find a person by Id ( use any of the above methods ) with the parameter
personId
as search key. Add "hamburger" to the list of her favoriteFoods
(you can use Array.push()). Then - inside the find callback - .save()
the updated Person
.
[*] Hint: This may be tricky if in your Schema
you declared
favoriteFoods
as an Array
without specifying the type (i.e. [String]
).
In that case favoriteFoods
defaults to Mixed
type, and you have to
manually mark it as edited using document.markModified('edited-field')
(http:mongoosejs.comdocsschematypes.html - #Mixed )
-
- New Update : Use
findOneAndUpdate()
-
- New Update : Use
Recent versions of mongoose
have methods to simplify documents updating.
Some more advanced features (i.e. prepost hooks, validation) beahve
differently with this approach, so the 'Classic' method is still useful in
many situations. findByIdAndUpdate()
can be used when searching by Id.
Find a person by name
and set her age to 20
. Use the function parameter
personName
as search key.
Hint: We want you to return the updated document. In order to do that
you need to pass the options document { new: true }
as the 3rd argument
to findOneAndUpdate()
. By default the method
passes the unmodified object to its callback.
-
- Delete one Person -
Delete one person by her -id
. You should use one of the methods
findByIdAndRemove()
or findOneAndRemove()
. They are similar to the
previous update methods. They pass the removed document to the cb.
As usual, use the function argument personId
as search key.
-
- Delete many People -
Model.remove()
is useful to delete all the documents matching given criteria.
Delete all the people whose name is "Mary", using Model.remove()
.
Pass to it a query ducument with the "name" field set, and of course a callback.
Note: Model.remove()
doesn't return the removed document, but a document
containing the outcome of the operation, and the number of items affected.
Don't forget to pass it to the done()
callback, since we use it in tests.
-
- Chain Query helpers -
If you don't pass the callback
as the last argument to Model.find()
(or to the other similar search methods introduced before), the query is
not executed, and can even be stored in a variable for later use.
This kind of object enables you to build up a query using chaining syntax.
The actual db search is executed when you finally chain
the method .exec()
, passing your callback to it.
There are many query helpers, here we'll use the most 'famous' ones.
Find people who like "burrito". Sort them alphabetically by name,
Limit the results to two documents, and hide their age.
Chain .find()
, .sort()
, .limit()
, .select()
, and then .exec()
,
passing the done(err, data)
callback to it.
var queryChain - function(done) { var foodToSearch - "burrito";
-
Well Done !!
-
You completed these challenges, let's go celebrate !
If you are eager to learn and want to go deeper, You may look at :
- Indexes ( very important for query efficiency ),
- PrePost hooks,
- Validation,
- Schema Virtuals and Model, Static, and Instance methods,
- and much more in the mongoose docs