Advanced Mongoose
#
Lesson Objectives- Use helper functions to make your life easier
- Extend the abilities of models
- Extend the abilities of classes
- Create a schema for properties of models that are objects
- Reference other models by id
- Create actions for models to execute during database actions
- Use indexes to speed up searches
#
Use helper functions to make your life easierMongoose's default find gives you an array of objects. But what if you know you only want one object? These convenience methods just give you one object without the usual array surrounding it.
Article.findById("5757191bce5579b805705900", (err, article) => { console.log(article);});
Article.findOne({ author: "Matt" }, (err, article) => { console.log(article);});
Article.findByIdAndUpdate( "5757191bce5579b805705900", // id of what to update { $set: { author: "Matthew" } }, // how to update it { new: true }, // tells findOneAndUpdate to return modified article, not the original (err, article) => { console.log(article); });
Article.findOneAndUpdate( { author: "Matt" }, // search criteria of what to update { $set: { author: "Matthew" } }, // how to update it { new: true }, // tells findOneAndUpdate to return modified article, not the original (err, article) => { console.log(article); });
Article.findByIdAndRemove("5757191bce5579b805705900", (err, article) => { console.log(article); // log article that was removed});
Article.findOneAndRemove({ author: "Matt" }, (err, article) => { console.log(article); // log article that was removed});
#
Extend the abilities of modelsYou can give all models using a specific schema extra properties and methods when creating that schema
// after initial schema declarationarticleSchema.methods.longTitle = () => { return this.author + ": " + this.title;};
// instantiate a model and then call itconst article = new Article();console.log(article.longTitle());
#
Extend the abilities of classesYou can create static methods for model constructor functions in their schema
// after initial schema declarationarticleSchema.statics.search = function (name, cb) { // because we use this here, we'll need an old-fashioned function // In this situation, it's like .find(), but it searches both title and author return this.find( { $or: [ { title: new RegExp(name, "i") }, { author: new RegExp(name, "i") }, ], }, cb );};
// call the static methodArticle.search("Some", (err, data) => { console.log(data);});
#
Reference other models by idSub docs are difficult when it comes to updating, because all duplicates must be updated. But we can reference by ID to get around this.
#
Single ObjectId referenceconst mongoose = require("mongoose");const Schema = mongoose.Schema;mongoose.connect("mongodb://localhost:27017/test");
const articleSchema = new Schema({ title: { type: String }, author: { type: Schema.Types.ObjectId, ref: "Author" }, //the author property is just an id of another object});
const authorSchema = new Schema({ name: { type: String },});
const Article = mongoose.model("Article", articleSchema);const Author = mongoose.model("Author", authorSchema);
const matt = new Author({ name: "Matt" });matt.save(() => { const article1 = new Article({ title: "Awesome Title", author: matt._id }); article1.save(() => { showAll(); });});
const showAll = () => { Article.find() .populate("author") .exec((error, article) => { //dynamically switch out any ids with the objects they reference console.log(article); mongoose.connection.close(); });};
#
Arrays of ObjectId referencesWe can do the same with arrays of ids
const authorSchema = new Schema({ name: { type: String }, articles: [{ type: Schema.Types.ObjectId, ref: "Articles" }],});
const Article = mongoose.model("Article", articleSchema);const Author = mongoose.model("Author", authorSchema);
const matt = new Author({ name: "Matt" });let article_id;matt.save(() => { let article1 = new Article({ title: "Awesome Title", author: matt._id }); article1.save(() => { article_id = article1._id; matt.articles.push(article1); matt.save(showAll); });});
var showAll = (err, author) => { Author.find() .populate("articles") .exec((err, authors) => { //dynamically switch out any ids with the objects they reference console.log(authors); mongoose.connection.close(); });};
#
Create actions for models to execute during database actionsWe can perform actions before and after database work
articleSchema.pre("save", function (next) { //because we use this here, we'll need an old-fashioned function console.log(this); console.log("saving to backup database"); next();});
async
articleSchema.pre("save", true, function (next) { //because we use this here, we'll need an old-fashioned function console.log(this); console.log("saving to backup database"); next(); doAsync(done);});
post
articleSchema.post("save", function (next) { //because we use this here, we'll need an old-fashioned function console.log("saving complete");});