Mục lục
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() gì đó 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 convertToTrue và convertToFalse để 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.