Mongoose Schema – SchemaTypes

Có thể nói rằng mọi thứ trong mongoose đều bắt đầu từ Schema. Mỗi Schema là một ánh xạ của collection trong MongoDB, định nghĩa toàn bộ những thông tin của collection như các field, kiểu dữ liệu của chúng, các hàm validate dữ liệu etc.

import mongoose from 'mongoose';

const UserSchema = mongoose.Schema({
    email: String,
    password: String,
    fullname: String,
    gender: {
        type: String,
        enum: ['male', 'female', 'other']
    },
    createdAt: {
        type: Date,
        default: Date.now
    },
    note: String
});

Ở trên là một ví dụ cơ bản về tạo một UserSchema gồm field như email, password, fullname etc và kiểu dữ liệu tương ứng của chúng như String, Date etc.

Schema Type

Các kiểu dữ liệu được mình nêu trong ví dụ trên là một phần trong những kiểu dữ liệu mà mongoose hỗ trợ. Dưới đây là các kiểu dữ liệu SchemaTypes trong mongoose:

  • String 
  • Number
  • Date
  • Buffer
  • Boolean
  • Mixed
  • ObjectId
  • Array
  • Decimal128
  • Map

String

Để khai báo một field String trong mongoose chúng ta có thể khai báo theo các cách sau

const schema1 = new mongoose.Schema({ name: String }); // name will be cast to string

const schema2 = new mongoose.Schema({ name: 'String' }); 

const schema3 = new mongoose.Schema({name: { type: String }})

Nếu bạn truyền đối tượng có method toString(), Mongoose sẽ gọi đến nó để lấy giá trị String cho field name. 

new Person({ name: 42 }).name; // mongoose sẽ cast 42 thành "42"
new Person({ name: { toString: () => 42 } }).name; // mongoose sẽ gọi method toString() và chuyển 42 thành "42"

// "undefined", Nếu save() Person chúng ta sẽ nhận lại exception từ mongoose
new Person({ name: { foo: 42 } }).name;

Number

Để khai báo field Number trong Mongoose như sau:

const schema1 = new mongoose.Schema({ age: Number });

const schema2 = new mongoose.Schema({ age: 'Number' });

Một số trường hợp đặc biệt sẽ được chuyển thành Number thành công mà chúng ta cần để ý như

new Car({ age: '15' }).age; // 15 as a Number
new Car({ age: true }).age; // 1 as a Number
new Car({ age: false }).age; // 0 as a Number
new Car({ age: { valueOf: () => 83 } }).age; // 83 as a Number

Giá trị false sẽ được chuyển thành 0, true thành 1. Và nếu đối tượng truyền vào có chứa method valueOf()Mongoose sẽ gọi nó để lấy giá trị trả về cho field tương ứng. Như ở trên new Car({ age: { valueOf: () => 83 } }).age thì age sẽ có giá trị là 83.

Date

const schema = new mongoose.Schema({ age: Date });

Buffer

Khai báo field Buffer trong mongoose chúng ta có thể dùng Buffer hoặc ‘Buffer’ Mongoose đều hiểu.

const schema1 = new mongoose.Schema({ binData: Buffer }); // binData will be cast to a Buffer
const schema2 = new mongoose.Schema({ binData: 'Buffer' });

Ví dụ 

const file1 = new Data({ binData: 'test'}); // {"type":"Buffer","data":[116,101,115,116]}
const file2 = new Data({ binData: 72987 }); // {"type":"Buffer","data":[27]}
const file4 = new Data({ binData: { type: 'Buffer', data: [1, 2, 3]}}); // {"type":"Buffer","data":[1,2,3]}

Mixed

Một “anything goes” của SchemaTyoe. Mongoose sẽ không làm bất cứ điều gì trên các field này kể cả cast. Để khai báo field Schema.Types.Mixed trong Mongoose có các cách sau:

const Any = new mongoose.Schema({ any: {} });
const Any = new mongoose.Schema({ any: Object });
const Any = new mongoose.Schema({ any: Schema.Types.Mixed });
const Any = new mongoose.Schema({ any: mongoose.Mixed });
const Any = new mongoose.Schema({
  any: {
    type: { foo: String }
  }
});

Với những field có type là Mixed bạn có thể thay đổi nó bất cứ thứ gì String, Number, Array, etc.

Lưu ý đối với những dữ liệu Mixed thì Mongoose sẽ không quản lý việc nó có thay đổi hay không trừ khi bạn gọi doc.markModified(path) thì Mongoose mới quan tâm và update chúng khi bạn save() Document.

person.anything = { x: [3, 4, { y: "changed" }] };
person.markModified('anything');
person.save(); // Mongoose sẽ update giá trị anything xuống database

Các hàm save() đó các bạn sẽ tìm hiểu ở phần sau, ý mình muốn các bạn hiểu idea mongoose nó sẽ làm gì thôi, nên cũng đừng băng khoăn về nó quá nhiều. Hiểu đơn giản nó dùng để lưu dữ liệu xuống database vậy thôi =))).

ObjectId

Thông thường với mỗi Schema chúng ta định nghĩa ra thì mongoose sẽ tự động thêm một filed _id có type ObjectId và nó tự generate cho mỗi document được thêm mới vào database và các ObjectId này sẽ là unique.

Để khai khái field có type là ObjectId như sau

import mongoose from 'mongoose';
var Car = new Schema({ driver: mongoose.Schema.Types.ObjectId });

Đối với ObjectId này các bạn bắt buộc phải ghi đầy đủ là mongoose.Schema.Types.ObjectId Không giống như String, Number vì những dữ liệu này được hỗ trợ sẵn trong javascript.

Boolean

Kiểu dữ liệu Boolean có giá trị true hoặc false trong Mongoose thế nhưng có một vài trường hợp Mongoose vẫn sẽ cast thành công sang giá trị true:

  • true
  • ‘true’
  • 1
  • ‘1’
  • ‘yes’

Các trường hợp được cast thành công sang false:

  • false
  • ‘false’
  • 0
  • ‘0’
  • ‘no’

Ngoài ra bạn còn có thể sử dụng method convertToTrueconvertToFalse để thêm các giá trị có thể được chuyển thành true hoặc false tương ứng ngoài các trường hợp mặc định trên.

const M = mongoose.model('Test', new Schema({ b: Boolean }));
console.log(new M({ b: 'haha' }).b); // undefined

// Set { false, 'false', 0, '0', 'no' }
console.log(mongoose.Schema.Types.Boolean.convertToFalse);

mongoose.Schema.Types.Boolean.convertToFalse.add('haha');
console.log(new M({ b: 'haha' }).b); // false

Array

Mongoose hỗ trợ một mảng các SchemaType như String, Number, Boolean, hoặc là một subDocument(một Schema khác).

var ToySchema = new mongoose.Schema({ name: String });
var ToyBoxSchema = new Schema({
  toys: [ToySchema],
  buffers: [Buffer],
  strings: [String],
  numbers: [Number]
});

Để khai báo kiểu array trong mongoose chúng ta sử dụng cặp dấu []. Để ý thấy ToySchema là một Schema và là subdocument của ToyBoxSchema.

Map

Trong Mongoose Map, kiểu dữ liệu của Key luôn là String bạn có thể chỉ định kiểu dữ liệu của Value với of.

const userSchema = new mongoose.Schema({
  socialMediaHandles: {
    type: Map,
    of: String
  }
}

Chúng ta có socialMediaHandles Map với value có kiểu dữ liệu là String.

Ví dụ

const User = mongoose.model('User', userSchema);

console.log(new User({
  socialMediaHandles: {
    github: 'devjoyvn',
    twitter: 'deftblog'
  }
}).socialMediaHandles);

Output: Map {‘github’ => ‘devjoyvn’, ‘twitter’ => ‘deftblog’}

Để thêm cặp key – value vào Map chúng ta sử dụng method set().

const user = new User({
  socialMediaHandles: {}
});


user.socialMediaHandles.set('github', 'devjoyvn');
// or 
user.set('socialMediaHandles.github', 'devjoyvn');

Để lấy giá trị bởi một key trong Map chúng ta sử dụng method get().

console.log(user.socialMediaHandles.get('github')); // devjoyvn

console.log(user.get('socialMediaHandles.github')); // devjoyvn

Decimal128

Để hỗ trợ cho việc lưu các số thập phân, ví dụ như các bạn cần lưu tiên lương, chi phí sinh hoạt, số bitcoin =) hiện có thì nên dùng Decimal128 để có được độ chính xác cao. 

const Staff = new mongoose.Schema({ salary: mongoose.Decimal128 });

Kết

Như vậy thì chúng ta đã tìm hiểu được cách tạo một Schema trong Mongoose, các kiểu dữ liệu và cách dùng của nó. Ở bài sau, mình sẽ giới thiệu về cách tạo ra một Model từ Schema cách thêm instance method, static method etc.

Các bài viết liên quan:

  1. Instance method trong mongoose
  2. Static method trong mongoose
  3. Query helper trong mongoose
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x