Databases
Presentation Tier
Business Tier
Data Tier
JSP
EJB
Oracle
Electron
Business Tier
Data Tier
Business Tier
Data Tier
Business Tier
Data Tier
ROUTER
View
View
Java
SQL based DB
View
Presentation Tier
React
React
React
React
Scaled static server/ CDN
Node
Node
Node
Node
ELB
Business Tier
Scaled Node.js services
Data Tier
Data tier
Scalable DB?
Significant increases in data volume
Data security
Managing and maintaining the database and infrastructure
Removing limits on scalability
CAP theorem, also named Brewer's theorem after computer scientist Eric Brewer, states that it is impossible for a distributed data store to simultaneously provide more than two out of the following three guarantees:
Slack
Strong Consistency offers up-to-date data but at the cost of high latency
WAIT FOR THE INTERNET TO START WORKING AGAIN
Eventual consistency offers low latency but may reply to read requests with stale data since all nodes of the database may not have the updated data.
Anser based on available data
Available
Not available
1
2
SQL Databases
NoSQL Databases
Generally speaking, NoSQL solutions have lighter weight transactional semantics than relational databases, but still have facilities for atomic operations at some level.
Answer following questions
Scale: may not be needed
Consistency: eventual is fine
Availability: not critical
Scale: critical
Consistency: eventual is fine
Availability: critical
Scale: critical
Consistency: Strong
Availability: less important
ACID: yes
Scale: critical
Consistency: strong
Availability: still important
The Hitchhiker's Guide to the Galaxy
Mongo-DB is a document database which provides high performance, high availability and easy scalability.
MongoDB allows a highly flexible and scalable document structure. For e.g. one data document in MongoDB can have five columns and the other one in the same collection can have ten columns. Also, MongoDB database are faster as compared to SQL databases due to efficient indexing and storage techniques.
No. MongoDB does not support such relationships.
MongoDB, has always supported ACID transactions in a single document and, when leveraging the document model appropriately, many applications don't need ACID guarantees across multiple documents
To achieve concepts of transaction and locking in MongoDB, we can use the nesting of documents, also called embedded documents. MongoDB supports atomic operations within a single document.
And that’s true. But it doesn’t mean that there is no schema.
db.createCollection("students", {
validator: {
$jsonSchema: {
bsonType: "object",
required: [ "name", "year", "major", "address" ],
properties: {
name: {
bsonType: "string",
description: "must be a string and is required"
},
year: {
bsonType: "int",
minimum: 2017,
maximum: 3017,
description: "must be an integer in [ 2017, 3017 ] and is required"
},
major: {
enum: [ "Math", "English", "Computer Science", "History", null ],
description: "can only be one of the enum values and is required"
},
gpa: {
bsonType: [ "double" ],
description: "must be a double if the field exists"
},
address: {
bsonType: "object",
required: [ "city" ],
properties: {
street: {
bsonType: "string",
description: "must be a string if the field exists"
},
city: {
bsonType: "string",
description: "must be a string and is required"
}
}
}
}
}
}
})
db.students.insert({
name: "Alice",
year: NumberInt(2019),
major: "History",
gpa: 3.0,
address: {
city: "NYC",
street: "33rd Street"
}
})
Issue the following command to add a validator to the contacts collection:
db.runCommand( {
collMod: "contacts",
validator: { $jsonSchema: {
bsonType: "object",
required: [ "phone", "name" ],
properties: {
phone: {
bsonType: "string",
description: "must be a string and is required"
},
name: {
bsonType: "string",
description: "must be a string and is required"
}
}
} },
validationLevel: "moderate"
} )
Indexes are special structures in MongoDB, which stores a small portion of the data set in an easy to traverse form. Ordered by the value of the field specified in the index, the index stores the value of a specific field or set of fields.
Loss in developer productivity whilst they learn to program with ORM.
Developers lose understanding of what the code is actually doing - the developer is more in control using SQL
ORM has a tendency to be slow
ORM fail to compete against SQL queries for complex queries.
which one to use?
docker run -d mongo
docker ps
docker inspect 835af70ea08a # mongo id
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "e9acd2b3a9fa0abe80af842b20860f546bd557644b75c25f35476c0bc849b09c",
"EndpointID": "f887ce1095db8138e5159dd87200789b9e52b13f1f2bf378a07195aeb8bec8de",
"Gateway": "10.10.1.1",
"IPAddress": "10.10.1.3", <--------------------
"IPPrefixLen": 24,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:0a:0a:01:03",
"DriverOpts": null
}
}
}
mongo --host 10.10.1.3
> show dbs
> use TestDB
> db.dropDatabase()
> use users
> db.users.insert([{...}])
> show collections
> db.find().pretty()
> db.users.findOne()
[
'{{repeat(15, 17)}}',
{
_id: '{{objectId()}}',
isActive: '{{bool()}}',
age: '{{integer(20, 40)}}',
username: '{{firstName()}}',
email: '{{email()}}',
claims: ['asd']
}
]
Generate some data https://www.json-generator.com/
db.users.deleteOne( {"_id": ObjectId("4d512b45cc9374271b02ec4f")});
db.users.update(
{ _id: 1 },
{
$inc: { age: 5 },
$set: {
item: "ABC123",
"info.publisher": "2222",
tags: [ "software" ],
"ratings.1": { by: "xyz", rating: 3 }
}
}
)
Update & delete
db.users.find(
{
"$or": [
{ "age": { "$gte": 20 } }
{ "active": true }
]
},
{
"username": 1,
"_id": 0
}
).limit(3).explain("executionStats")
db.users.ensureIndex({ "age": 1 })
db.users.getIndexes()
db.users.dropIndex({ "age": 1 })
Find query & indexes
db.sales.insertMany([
{ '_id' : 1, 'item' : 'abc', 'price' : 10, 'quantity' : 2, 'date' : new Date('2014-03-01T08:00:00Z') },
{ '_id' : 2, 'item' : 'jkl', 'price' : 20, 'quantity' : 1, 'date' : new Date('2014-03-01T09:00:00Z') },
{ '_id' : 3, 'item' : 'xyz', 'price' : 5, 'quantity' : 10, 'date' : new Date('2014-03-15T09:00:00Z') },
{ '_id' : 4, 'item' : 'xyz', 'price' : 5, 'quantity' : 20, 'date' : new Date('2014-04-04T11:21:39.736Z') },
{ '_id' : 5, 'item' : 'abc', 'price' : 10, 'quantity' : 10, 'date' : new Date('2014-04-04T21:23:13.331Z') },
{ '_id' : 6, 'item' : 'def', 'price' : 7.5, 'quantity': 5, 'date' : new Date('2015-06-04T05:08:13Z') },
{ '_id' : 7, 'item' : 'def', 'price' : 7.5, 'quantity': 10, 'date' : new Date('2015-09-10T08:43:00Z') },
{ '_id' : 8, 'item' : 'abc', 'price' : 10, 'quantity' : 5, 'date' : new Date('2016-02-06T20:20:13Z') },
]);
const aggregation = [
{ $match: { quantity: { $gte: 10 } } },
{ $group: { _id : null, avg: { $avg: '$price' } } }
];
db.sales.aggregate(aggregation);
Aggregation
yarn add @nestjs/mongoose mongoose
Once the installation process is complete, we can import the MongooseModule into the root AppModule.
@Module({
imports: [
UsersModule,
ConfigModule.forRoot(),
MongooseModule.forRoot('mongodb://10.10.1.3/users'),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
The forRoot() method accepts the same configuration object as mongoose.connect() from the Mongoose package
import { MongooseModule } from '@nestjs/mongoose';
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { User, UserSchema } from './schemas/user.schema';
@Module({
imports: [
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
controllers: [UsersController],
providers: [
{
provide: 'IUsersService',
useClass: UsersService,
},
],
})
export class UsersModule {}
Users module
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
import { Permissions } from '../enums/Permissions';
@Schema({ timestamps: true })
export class User {
@Prop({ unique: true })
username: string;
@Prop({ unique: true, index: true })
email: string;
@Prop({ default: true })
active: boolean;
@Prop({
enum: Permissions,
type: [String],
default: [Permissions.WRITE_TEXTS],
})
claims: string[];
}
export type UserDocument = User & Document;
export const UserSchema = SchemaFactory.createForClass(User);
import { UserDocument } from './../schemas/user.schema';
import { User } from '../schemas/user.schema';
import { CreateUserDto } from '../dto/create-user.dto';
import { UpdateUserDto } from '../dto/update-user.dto';
export interface IUsersService {
create(createUserDto: CreateUserDto): Promise<User>;
findAll(): Promise<UserDocument[]>;
findOne(id: string): Promise<User>;
update(id: string, updateUserDto: UpdateUserDto): Promise<User>;
remove(id: string): Promise<string>;
}
import { User, UserDocument } from './schemas/user.schema';
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { IUsersService } from './interfaces/IUserService';
import { v4 as uuid } from 'uuid';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
@Injectable()
export class UsersService implements IUsersService {
private readonly logger = new Logger(UsersService.name);
constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) {}
async create(createUserDto: CreateUserDto) {
const createdUser = new this.userModel(createUserDto);
return createdUser.save();
}
async findAll() {
return this.userModel.find();
}
async findOne(id: string) {
const user = this.userModel.findById(id);
if (!user) {
this.logger.warn(`User with id ${id} doen't exist`);
this.logger.error(`User with id ${id} doen't exist`);
this.logger.debug(`User with id ${id} doen't exist`);
throw new NotFoundException(`User with id ${id} doen't exist`);
}
return user;
}
async update(id: string, updateUserDto: UpdateUserDto) {
const user = await this.findOne(id);
user.username = updateUserDto.username ?? user.username;
user.email = updateUserDto.email ?? user.email;
return user.save();
}
async remove(id: string) {
const user = await this.findOne(id);
user.remove();
return id;
}
}