Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[nodejs] MongoDB and Mongoose Challenges

These are my notes while doing the course APIs and Microservices on https://www.freecodecamp.org. I highly recommend it if you prefer to try things directly rather than watching videos.


MongoDB is a database that stores data records (documents) for use by an application. Mongo is a non-relational, “NoSQL” database. This means Mongo stores all associated data within one record, instead of storing it across many preset tables as in a SQL database.
Mongo’s use of JSON as its document storage structure makes it a logical choice when learning backend JavaScript. Accessing documents and their properties is like accessing objects in JavaScript.

Mongoose.js is an npm module for Node.js that allows you to write objects for Mongo as you would in JavaScript.

MongoDB Atlas is a MongoDB Database-as-a-Service platform.


Install and Set Up Mongoose

Add mongodb and mongoose to the project’s package.json.

    "dependencies": {
        "body-parser": "^1.15.2",
        "dotenv": "^8.2.0",
        "express": "^4.12.4",
        "mongodb": "^3.6.4",
        "mongoose": "^5.11.15"
    },

Store your MongoDB Atlas database URI in a private .env file as MONGO_URI. Replace user and password.

MONGO_URI=mongodb+srv://<User>:<Password>@cluster0.xvsqx.mongodb.net/<dbname>?retryWrites=true&w=majority

Connect to the database using the following syntax:

const mongoose = require('mongoose');
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });

Create a Model

Everything in Mongoose starts with a Schema. Each schema maps to a MongoDB collection and defines the shape of the documents within that collection.

const { Schema } = mongoose;

const personSchema = new Schema({
  name: { type: String, required: true },
  age: Number,
  favoriteFoods: [String]
});

const Person = mongoose.model("Person", personSchema);

Create and Save a Record of a Model

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 as done(null, data) on success, or done(err) on error.

const createAndSavePerson = (done) => {

  let max = new Person({name: "Max", age: 31, favoriteFoods: ["Pasta"]});

  max.save((err, data) => {
    if (err) return console.error(err);
    done(null, data)
  });

};

Create Many Records with model.create()

var arrayOfPeople = [
    {name: "Max", age: 31, favoriteFoods: ["Pasta"]},
    {name: "Toni", age: 21, favoriteFoods: ["Pizza"]},
    {name: "Paul", age: 34, favoriteFoods: ["Bolo", "Penne"]}
    ];

const createManyPeople = (arrayOfPeople, done) => {
  Person.create(arrayOfPeople, (err, people) => {
    if (err) return console.error(err);
    done(null, people);
  });
};

Use model.find() to Search Your Database

Model.find() accepts a query document (a JSON object) as the first argument, then a callback. It returns an array of matches.

const findPeopleByName = (personName, done) => {
  Person.find({name: personName}, (err, personFound) => {
    if (err) return console.error(err);
    done(null, personFound);
  })
};

Use model.findOne() to Return a Single Matching Document from Your Database

Model.findOne() behaves like Model.find(), but it returns only one document (not an array), even if there are multiple items.

const findOneByFood = (food, done) => {
  Person.findOne({favoriteFoods: food}, (err, personFound) => {
    if (err) return console.error(err);
    done(null, personFound);
  })
};

Use model.findById() to Search Your Database By _id

When saving a document, MongoDB automatically adds the field _id, and set it to a unique alphanumeric key.

const findPersonById = (personId, done) => {
  Person.findById({_id: personId}, (err, personFound) => {
    if (err) return console.error(err);
    done(null, personFound);
  })
};

Perform Classic Updates by Running Find, Edit, then Save

const findEditThenSave = (personId, done) => {
  const foodToAdd = 'hamburger';

  Person.findById(personId, (err, person) => {
    if(err) return console.log(err); 
  
    person.favoriteFoods.push(foodToAdd);
    person.save((err, updatedPerson) => {
      if(err) return console.log(err);
      done(null, updatedPerson)
    })
  })
};

Perform New Updates on a Document Using model.findOneAndUpdate()

Use the function parameter personName as the search key. Set the person’s age to 20.
Note: You should return the updated document. To do that, you need to pass the options document { new: true } as the 3rd argument to findOneAndUpdate(). By default, these methods return the unmodified object.

const findAndUpdate = (personName, done) => {
  const ageToSet = 20;

  Person.findOneAndUpdate({name: personName}, {age: ageToSet}, { new: true }, (err, updatedDoc) => {
    if (err) return console.error(err);
    done(null, updatedDoc)
  })
};

Delete One Document Using model.findByIdAndRemove()

const removeById = (personId, done) => {

  Person.findByIdAndRemove(personId, (err, personDeleted) => {
    if (err) return console.error(err);
    done(null, personDeleted)
  })
};

Delete Many Documents with model.remove()

const removeManyPeople = (done) => {
  const nameToRemove = "Mary";

  Person.remove({name: nameToRemove}, (err, personsDeleted) => {
    if (err) return console.error(err);
    done(null, personsDeleted)
  })
};

Chain Search Query Helpers to Narrow Search Results

const queryChain = (done) => {
  const foodToSearch = "burrito";

  Person.find({favoriteFoods: foodToSearch})
  .sort({name: 1}) //sort bei name
  .limit(2) //only 2 results
  .select({age: 0})  //hide age
  .exec((err, twoPersonFound) => {
    if (err) return console.error(err);
    done(null, twoPersonFound)
  })
};