- MongoDB stores data in flexible, JSON-like documents
- The document model maps to the objects in your application code, making data easy to work with
- MongoDB is a distributed database at its core, so high availability, horizontal scaling, and geographic distribution are built in and easy to use
— BEST FOR ECOMMERSE + STARTUP & APPS like Snapchat or Instagram who need near by location of people
mongosh
show dbs use test show collections db.dropDatabase() cls exit
test>>db.users.insertOne({name: "John"}) //add json to users collection in test database db.users.find() //find all in users collections //nested field db.users.insertOne({ name: "Sally", age: 19, address: { street: "987 North St" }, hobbies: ["Running"] }) db.new.insertMany([{name:"mike"},{name:"jill"}]) //multiple insertion
db.new.find().limit(1) //limit no. of result db.new.find().sort({name: -1}) //sorting assending(1) or desending(-1) db.new.find().sort({age: 1,name: -1}) db.new.find().skip(1).limit(1) // can skip also db.new.find({name: kyle}) db.new.find({name: "Sally"}, {name: 1, age: 1}) //if i only want name,age db.new.find({name: "Sally"}, {name: 1, age: 1,_id:0}) //if i only want name,age also i don't want id db.new.find({name: "Sally"}, {age: 0}) //all fields except age db.users.find({ name: { $eq: "Sally" }}) //shell + DB (equal = eq) // shell include ne,gt,lt,gte,lte db.users.find({ name: { $in: ["Sally","robin"] }}) // similarly has nin - not in db.users.find({ age: { $exists: true }}) //only objects that have age db.users.find({ name: { $gte: 20, $lte:25 }}) //two condition db.users.find({ age: { $gte: 20, $lte: 40 }, name: "Sally" }) //multi condition db.users.find({ $and: [{age: 26 }, { name: "Kyle" }] }) //and operation need array //also can have or , not db.users.find({ age: { $not: { $lte: 20 } }}) // not
$ sign before column
>>db.users.insertMany([{ name: "Tom", balance: 100, debt: 200 }, { name: "Kristin", balance: 20, debt: 0}]) >> db.users.find({$expr: { $gt: ["$debt", "$balance"]} })
db.users.find({ "address.street": "123 Main St" }) db.users.countDocuments({ age: { $lte: 40 }})
Update
$set - to update property
db.users.updateOne({age: 26}, { $set: { age: 27 } }) db.users.updateOne({ _id: ObjectId("6112809d7ec144c25156c4dd")}, { $set: { name: "New Name" } }) //increment db.users.updateOne({ _id: ObjectId("6112809d7ec144c25156c4dd") }, { $inc: { age: 3 }}) //change the name of property db.users.updateOne({ _id: ObjectId("6112809d7ec144c25156c4dd") }, { $rename: { name: "firstName" }}) //remove perticular property db.users.updateOne({ _id: ObjectId("6112809d7ec144c25156c4dd") }, { $unset: { age: ' } }) //add new property db.users.updateOne({ _id: ObjectId("6112809d7ec144c25156c4dd") }, { $push: { hobbies: "Swimming" } }) //remove perticular data from property db.users.updateOne({ _id: ObjectId("6112809d7ec144c25156c4dd") }, { $pull: { hobbies: "Bowling" } }) db.users.updateMany({address: {$exists: true}},{$unset: {address: ""}}) //replace everything at location & delete all and add new one db.users.replaceOne({age: 30},{name:"john"}) //delete db.users.deleteOne({ name: "John" }) //deleteMany db.users.deleteMany({ age: { $exists: false} })
Mongoose
Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js. It manages relationships between data, provides schema validation, and is used to translate between objects in code and the representation of those objects in MongoDB.
Schema
A Mongoose schema is a document data structure (or shape of the document) that is enforced via the application layer.
const puppySchema = new mongoose.Schema({ name: { type: String, required: true }, age: Number });
Models
Models are higher-order constructors that take a schema and create an instance of a document equivalent to records in a relational database.
const Puppy = mongoose.model('Puppy', puppySchema);
NPM Install
npm init -y npm install mongoose validator
Database Connection
Database
class into a singleton by returning an instance of the class in the module.exports
statement because we only need a single connection to the database.let mongoose = require('mongoose'); const server = '127.0.0.1:27017'; // REPLACE WITH YOUR DB SERVER const database = 'fcc-Mail'; // REPLACE WITH YOUR DB NAME class Database { constructor() { this._connect(); } _connect() { mongoose .connect(`mongodb://${server}/${database}`) .then(() => { console.log('Database connection successful'); }) .catch((err) => { console.error('Database connection error'); }); } } module.exports = new Database();
Validator library
validation function that will ensure that the value is a valid email address.
let mongoose = require('mongoose'); let validator = require('validator'); let emailSchema = new mongoose.Schema({ email: { type: String, required: true, unique: true, lowercase: true, validate: (value) => { return validator.isEmail(value); } } }); module.exports = mongoose.model('Email', emailSchema);
Create Record
create an instance of the email model and save it to the database
let EmailModel = require('./email'); let msg = new EmailModel({ email: 'ADA.LOVELACE@GMAIL.COM' }); msg .save() .then((doc) => { console.log(doc); }) .catch((err) => { console.error(err); });
>>>>Result
{ _id: 5a78fe3e2f44ba8f85a2409a, email: 'ada.lovelace@gmail.com', __v: 0 }
__v
is the version Key property set on each document when first created by Mongoose. Its value contains the internal revision of the document.
- The
_id
field is auto-generated by Mongo and is a primary key of the collection. Its value is a unique identifier for the document
Fetch Record
EmailModel.find({ email: 'ada.lovelace@gmail.com' // search query }) .then((doc) => { console.log(doc); }) .catch((err) => { console.error(err); });
Update Record
EmailModel.findOneAndUpdate( { email: 'ada.lovelace@gmail.com' // search query }, { email: 'theoutlander@live.com' // field:values to update }, { new: true, // return updated doc runValidators: true // validate before update } ) .then((doc) => { console.log(doc); }) .catch((err) => { console.error(err); });
Delete Record
EmailModel.findOneAndRemove({ email: 'theoutlander@live.com' }) .then((response) => { console.log(response); }) .catch((err) => { console.error(err); })
Helpers
create a user schema
let mongoose = require('mongoose'); let userSchema = new mongoose.Schema({ firstName: String, lastName: String }); module.exports = mongoose.model('User', userSchema);
Virtual Property
create a virtual property called
fullName
which can be used to set values on firstName
and lastName
and retrieve them as a combined value when readuserSchema.virtual('fullName').get(function () { return this.firstName + ' ' + this.lastName; }); userSchema.virtual('fullName').set(function (name) { let str = name.split(' '); this.firstName = str[0]; this.lastName = str[1]; });
>>>>>
let model = new UserModel(); model.fullName = 'Thomas Anderson'; console.log(model.toJSON()); // Output model fields as JSON console.log(); console.log(model.fullName); // Output the full name
>>>>> result
{ _id: 5a7a4248550ebb9fafd898cf, firstName: 'Thomas', lastName: 'Anderson' } Thomas Anderson
Instance Methods
create a function to return the initials for the current user. Let’s add a custom helper method called
getInitials
to the schemauserSchema.methods.getInitials = function () { return this.firstName[0] + this.lastName[0]; };
let model = new UserModel({ firstName: 'Thomas', lastName: 'Anderson' }); let initials = model.getInitials(); console.log(initials); // This will output: TA
Static Methods
we can create static methods on the schema. Let’s create a method to retrieve all users in the database
userSchema.statics.getUsers = function () { return new Promise((resolve, reject) => { this.find((err, docs) => { if (err) { console.error(err); return reject(err); } resolve(docs); }); }); };
getUsers
on the Model class will return all the users in the databaseMiddleware
Middleware are functions that run at specific stages of a pipeline
operations:
- Aggregate
- Document
- Model
- Query
For instance, models have
pre
and post
functions that take two parameters:- Type of event (‘init’, ‘validate’, ‘save’, ‘remove’)
- A callback that is executed with this referencing the model instance
example - adding two fields called
createdAt
and updatedAt
to our schemalet mongoose = require('mongoose'); let userSchema = new mongoose.Schema({ firstName: String, lastName: String, createdAt: Date, updatedAt: Date }); module.exports = mongoose.model('User', userSchema);
When
model.save()
is called, there is a pre(‘save’, …)
and post(‘save’, …)
event that is triggered. For the second parameter, you can pass a function that is called when the event is triggered. These functions take a parameter to the next function in the middleware chain.userSchema.pre('save', function (next) { let now = Date.now(); this.updatedAt = now; // Set a value for createdAt only if it is null if (!this.createdAt) { this.createdAt = now; } // Call the next function in the pre-save chain next(); });
let UserModel = require('./user'); let model = new UserModel({ fullName: 'Thomas Anderson' }); msg .save() .then((doc) => { console.log(doc); }) .catch((err) => { console.error(err); });
Plugins
Suppose that we want to track when a record was created and last updated on every collection in our database. Instead of repeating the above process, we can create a plugin and apply it to every schema.
create a plugin for timestamp
module.exports = function timestamp(schema) { // Add the two fields to the schema schema.add({ createdAt: Date, updatedAt: Date }); // Create a pre-save hook schema.pre('save', function (next) { let now = Date.now(); this.updatedAt = now; // Set a value for createdAt only if it is null if (!this.createdAt) { this.createdAt = now; } // Call the next function in the pre-save chain next(); }); };
To use this plugin, we simply pass it to the schemas that should be given this functionality:
let timestampPlugin = require('./plugins/timestamp'); emailSchema.plugin(timestampPlugin); userSchema.plugin(timestampPlugin);
Query Building
Consider a query where we can incrementally build query components.
UserModel.find() // find all users .skip(100) // skip the first 100 items .limit(10) // limit to 10 items .sort({ firstName: 1 }) // sort ascending by firstName .select({ firstName: true }) // select firstName only .exec() // execute the query .then((docs) => { console.log(docs); }) .catch((err) => { console.error(err); });