Step 11
Open NoteDao.js
file inside server/data
folder. We don't need the constructor of this class! We will be storing the data in MongoDB rather than an array.
Delete the constructor. Then, update the operations as follows:
Create
async create({ title, text }) {
if (title === undefined || title === "") {
throw new ApiError(400, "Every note must have a none-empty title!");
}
if (text === undefined) {
throw new ApiError(400, "Every note must have a text attribute!");
}
- const note = new Note(title, text);
- this.notes.push(note);
+ const note = await Note.create({ title, text });
return note;
}
Update
async update(id, { title, text }) {
- const index = this.notes.findIndex((note) => note._id === id);
+ const note = await Note.findByIdAndUpdate(
+ id,
+ { title, text },
+ { new: true, runValidators: true }
+ );
- if (index === -1) {
+ if (note === null) {
throw new ApiError(404, "There is no note with the given ID!");
}
- if (title !== undefined) {
- this.notes[index].title = title;
- }
- if (text !== undefined) {
- this.notes[index].text = text;
- }
- return this.notes[index];
+ return note;
}
The findByIdAndUpdate
is a built-in function by Mongoose. It takes three parameters:
-
id
: the ID of a note in your database to be updated. Ifid
does not match an existing note, thefindByIdAndUpdate
will return null. -
An object containing the new attributes (and their values) which are to replace the existing attribute values of the note to be updated. If any of these are undefined, the attribute will not change (so we don't need this if statements to guard against this scenario)
-
An object of parameters:
new: true
changes the default behavior offindByIdAndUpdate
to return the updated note (instead of the original one).runValidators: true
changes the default behavior offindByIdAndUpdate
to force running validators on new attributes. If validation fails, thefindByIdAndUpdate
operation throws an error.
Delete
async delete(id) {
- const index = this.notes.findIndex((note) => note._id === id);
+ const note = await Note.findByIdAndDelete(id);
- if (index === -1) {
+ if (note === null) {
throw new ApiError(404, "There is no note with the given ID!");
}
- const note = this.notes[index];
- this.notes.splice(index, 1);
return note;
}
The findByIdAndDelete
will delete and return the deleted note if the id
exists in the database. Otherwise, it will return null
.
Read
// returns an empty array if there is no note with the given ID
async read(id) {
- return this.notes.find((note) => note._id === id);
+ const note = await Note.findById(id);
+ return note ? note : [];
}
The findById
will return null
if there is no note with the give ID.
// returns an empty array if there is no note in the database
// or no note matches the search query
async readAll(query = "") {
if (query !== "") {
- return this.notes.filter(
- (note) => note.title.includes(query) || note.text.includes(query)
- );
+ const notes = await Note.find().or([{ title: query }, { text: query }]);
+ return notes;
}
- return this.notes;
+ const notes = await Note.find({});
+ return notes;
}
The find
method takes an optional parameter, a filter, which can be used to search for notes that match the given attribute values. If we want to receive all notes, we can call find
with no argument or with an empty filter object.
Notice I have use the or
method, part of Mongoose's query builder language.
Note that the current query returns exact matches. You can also use regular expression to perform an contains
query.
- const notes = await Note.find().or([{ title: query }, { text: query }]);
+ const notes = await Note.find().or([{ title: { "$regex": query, "$options": "i" } }, { text: { "$regex": query, "$options": "i" } }]);
If there are no "notes" in the database, or there is no match for the filter we have provided, the find
method returns an empty array.
Here is the NodeDao.js
after all the refactoring!
const Note = require("../model/Note");
const ApiError = require("../model/ApiError");
class NoteDao {
constructor() {
this.notes = [];
}
async create({ title, text }) {
if (title === undefined || title === "") {
throw new ApiError(400, "Every note must have a none-empty title!");
}
if (text === undefined) {
throw new ApiError(400, "Every note must have a text attribute!");
}
const note = await Note.create({ title, text });
return note;
}
async update(id, { title, text }) {
const note = await Note.findByIdAndUpdate(
id,
{ title, text },
{ new: true, runValidators: true }
);
if (note === null) {
throw new ApiError(404, "There is no note with the given ID!");
}
return note;
}
async delete(id) {
const note = await Note.findByIdAndDelete(id);
if (note === null) {
throw new ApiError(404, "There is no note with the given ID!");
}
return note;
}
// returns an empty array if there is no note with the given ID
async read(id) {
const note = await Note.findById(id);
return note ? note : [];
}
// returns an empty array if there is no note in the database
// or no note matches the search query
async readAll(query = "") {
if (query !== "") {
const notes = await Note.find().or([{ title: query }, { text: query }]);
return notes;
}
const notes = await Note.find({});
return notes;
}
}
module.exports = NoteDao;