---
# System prepended metadata

title: MongoDB Notes
tags: [NoSQL, API, MongoDB, Linux, Database, System Design, Distributed System, Software, Server]

---

# MongoDB Notes
###### tags: `MongoDB` `Database` `NoSQL` `System Design` `Linux` `Server` `Distributed System` `Software` `API`

NoSQL x Nodejs backend development learning notes.

![](https://hackmd.io/_uploads/SyXks8QeT.png)

## Getting started

### MongoDB_Cli

- manual
  [mongosh Methods - MongoDB Manual](https://www.mongodb.com/docs/manual/reference/method/)
- ref
  [MongoDB 基礎入門教學：MongoDB Shell 篇 - G. T. Wang](https://blog.gtwang.org/programming/getting-started-with-mongodb-shell-1/)

### MongoDB_Nodejs

- manual
  [Index - MongoDB Node.JS Driver 1.4.9 documentation - github.io](https://mongodb.github.io/node-mongodb-native/genindex.html)
- cheetsheet
  [Quick Reference - Node.js - MongoDB](https://www.mongodb.com/docs/drivers/node/current/quick-reference/)
  [Query and Write Operation Commands - Database Command - MongoDB](https://www.mongodb.com/docs/manual/reference/command/nav-crud/)
- operation example [Usage Examples - Node.js - MongoDB](https://www.mongodb.com/docs/drivers/node/current/usage-examples/)
- useful tutorial
  [Fundamentals - Node.js - MongoDB](https://www.mongodb.com/docs/drivers/node/current/fundamentals/)
  [Node.js MongoDB Get Started - w3school](https://www.w3schools.com/nodejs/nodejs_mongodb.asp)

### Mongoose

- tutorial
  [Express Tutorial Part 3: Using a Database (with Mongoose) - mdn web docs](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose)
  [mdn / express-locallibrary-tutorial - github](https://github.com/mdn/express-locallibrary-tutorial/tree/main)
  [Mongoose Getting Started - mongoosejs](https://mongoosejs.com/docs/index.html)
- ref
  [Mongoose 資料操作 - 三步驟從 MongoDB 到 API - 林彥成](https://linyencheng.github.io/2019/09/07/tool-mongoose-mongo/)

## Operations

### Databases

#### use & statistic
```javascript=
// Cli
use myDB

db.stats();
```

### Users & Permissions

[為 MongoDB 加上驗證機制 - Yowko's Notes](https://blog.yowko.com/mongodb-enable-auth/)

#### create a administrator
```javascript=
// Cli
use admin

db.createUser(
{
    user: "adminname",
    pwd: "adminpassword",
    // here role only accepts "userAdmin" / "userAdminAnyDatabase"
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
});
```

#### create a user for test-db
```javascript=
// Cli
use test-db

db.createUser({
    user: "username",
    pwd: "userpassword",
    roles: [{ role: "readWrite", db: "test-db" }]
});
```

#### authentication
```javascript=
// Cli
db.auth("username", "userpassword");
```

#### list all users
```javascript=
// Cli
db.getUsers();
```

#### drop users
```javascript=
// Cli
db.dropAllUsers();
```

### Collections


same as SQL's Tables

| SQL      | MongoDB    |
| -------- | ---------- |
| Database | Database   |
| Table    | Collection |
| Row      | Document   |
| Column   | Field      |


#### insert
```javascript=
// if Collection "people" doesn't exist => automatically create one

// Cli
db.people.insertOne({
    "name": { "first": "J.J.", "last": "Fang"},
    "gender": "female",
    "age": 70
});
```

```javascript=
// Cli
db.people.insertMany([
    {
        "name": { "first": "J.J.", "last": "Lin"},
        "gender": "male",
        "age": 50
    },
    {
        "name": { "first": "E.E.", "last": "Tsai"},
        "gender": "female",
        "age": 66
    }
]);
```

#### find

[Query and Projection Operators - MongoDB Manual](https://www.mongodb.com/docs/manual/reference/operator/query/)
```javascript=
// Cli / Node.js
db.people.find({ "name.first": "J.J." });

db.people.find({ $or: [ { age: { $gt: 60 } }, { gender: "female" } ] });
```

#### list contents in the *Collection*
```javascript=
// Cli / Node.js
db.people.find();
```

#### list *Collections*
```javascript=
// Cli
db.getCollectionNames();

// Node.js
db.listCollections().toArray();
```

> Any operation in Node.js return *a cursor (pointer)* to this session query, then transform it *.toArray()*, *.sort()* ...
> For more information: [Cursor() — MongoDB Node.JS Driver 1.4.9 documentation](https://mongodb.github.io/node-mongodb-native/api-generated/cursor.html)

#### get *Collection* info
```javascript=
db.people.stats().size;
db.people.stats().count;

```

#### drop the *Collection*
```javascript=
db.people.drop();
```

## Mongoose

### Schemas

- [MongoDB Schema 設計指南 - Soul & Shell Blog](https://blog.toright.com/posts/4483/mongodb-schema-%E8%A8%AD%E8%A8%88%E6%8C%87%E5%8D%97.html)

![](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose/library_website_-_mongoose_express.png =500x)
Schemas have a few configurable options which can be passed to the constructor or to the set method:

```javascript=
new Schema({ field: String, ... }, { timestamps: true });

// or
const MySchema = new Schema({ field0: String, ... });
// Ex. MySchema.set("strict", true);
MySchema.set(option, value);  
// if field || field2 is unique  // (no need for field && field2 are both unique)
//   => validated
MySchema.index({ field: 1, field2: 1 }, { unique: true });
```

When *strict* option is set to true, Mongoose will ensure that only the fields that are specified in your Schema will be saved in the database, and all other fields will not be saved (if some other fields are sent). In simple term, the strict option, ensures that values passed to our model constructor that were not specified in our schema do not get saved to the db. Mongoose supports a separate strictQuery option to avoid strict mode for query filters. This is because empty query filters cause Mongoose to return all documents in the model, which can cause issues.

### Models

convenient for operate a Schema & some virtual methods

#### create a *Model* from a *Schema*
```javascript=
const MyObjSchema = new Schema({ ... });

// using virtual method: const str = obj.instanceFunc
MyObjSchema.virtual("instanceFunc").get(function () {
    return "/url/uuid/" + this._id;
});
MyObjSchema.virtual("instanceFunc2").get(function () {
    return this.field0;
});

const MyObjModel = mongoose.model("MyObject", MySchema);
// or
module.exports = mongoose.model("MyObject", MySchema);
```

#### insert new *Model instance* to db
```javascript=
const obj = new MyObjModel({ data: "..." });
await obj.save();
```

#### Mongoose *Model* built-in function
```javascript=
await Model.findById(id, "field0 field3").exec();  // exec return a Promise (suit for tracking error code)
await Model.findByIdAndRemove(id);
await Model.findOneAndRemove({ field: ... });
await Model.findByIdAndUpdate(id, obj);
await Model.findOneAndUpdate({ field: ... },{ field: "newValue" }, { upsert: true });

await model.updateOne({ field: ... })
await Model.updateOne({ name: /regex match/, 'field_model._id': id }, { $set: { field: "new value", 'field_model.$.field': ... } });
await Model.updateMany({}, { $rename: { oldFieldName: "newFieldName" } })
await Model.updateMany({}, { $pull: { field_models: field_model } })
await Model.updateMany({}, { $pull: { field_models: { field_model_field: /match/ } } })
await Model.updateMany({}, { $push: { field_models: field_model } })
await Model.deleteMany({field: ...});

model = await Model.findById(id);
model = await Model.findOne({ field: ... });
model = await Model.find({ field: ... }, "display_field display_field2");

count = await Model.countDocuments({ field: ... });
```

options:
- **new**: bool - true to return the modified document rather than the original. defaults to false
- **upsert**: bool - creates the object if it doesn’t exist. defaults to false.
- **overwrite**: bool - if true, replace the entire document.
- **fields**: { Object or String } - Field selection. Equivalent to .select(fields).findOneAndUpdate()
- **maxTimeMS**: puts a time limit on the query - requires mongodb >= 2.6.0
- **sort**: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
- **runValidators**: if true, runs update validators on this command. Update validators validate the update operation against the model’s schema.
- **setDefaultsOnInsert**: true by default. If setDefaultsOnInsert and upsert are true, mongoose will apply the defaults specified in the model’s schema if a new document is created.
- **rawResult**: if true, returns the raw result from the MongoDB driver
- **strict**: overwrites the schema’s strict mode option for this update

#### Schema's Middleware before / after Model's operations

Middleware (also called pre and post hooks) are functions which are passed control during execution of asynchronous functions. Middleware is specified on the schema level and is useful for writing [plugins](https://mongoosejs.com/docs/plugins.html).

[Middleware - mongoosejs.com](https://mongoosejs.com/docs/middleware.html)

 ##### pre
```javascript=
const schema = new Schema({ ... });
schema.pre('save', function(next) {
    ...
    return next();  // will make sure the rest doesn't run
    ...
});
```

##### post
```javascript=

schema.post('init', function(doc) {
  console.log('%s has been initialized from the db', doc._id);
});
```

## Tech Featuring

### Replica

For data redundancy & high availability

ref: [Replication - MongoDB](https://www.mongodb.com/docs/manual/replication/)

### Sharding

high global consistency vs. high access availability

- Read Concern
  [Read Concern - MongoDB](https://www.mongodb.com/docs/manual/reference/read-concern/)
- Write concern
  [Write Concern - MongoDB](https://www.mongodb.com/docs/manual/reference/write-concern/)

ref: [Sharding - MongoDB](https://www.mongodb.com/docs/manual/sharding/)

## Change Streams

Subscribe to all data changes on a single collection, a database, or an entire deployment in real time.

ref: [Change Streams - MongoDB](https://www.mongodb.com/docs/manual/changeStreams/)

### Periodical Data Consuming

Formulate a time-granularity-specified *Collection*

ref: [Time Series - MongDB](https://www.mongodb.com/docs/manual/core/timeseries-collections/#std-label-manual-timeseries-collection)
  
  