Create / Read / Update / Delete trong Mongoose
Trong bài này ta sẽ tìm hiểu về các cách thực thi create, read, update, delete trong Mongoose, những thao tác này còn gọi là CRUD. Chúng là những mongoose query object có nhiệm vụ làm việc với MongoDB.
1. Mongoose Query
Mongoose models cung cấp cho chúng ta một vài function cho phép thực hiện các hành động CRUD (Create, Read, Update, Delete). Các function này đều trả về một mongoose query obejct. Ở đây chúng ta có một vài hàm như sau :
- Model.deleteMany()
- Model.deleteOne()
- Model.find()
- Model.findById()
- Model.findByIdAndDelete()
- Model.findByIdAndRemove()
- Model.findByIdAndUpdate()
- Model.findOne()
- Model.findOneAndDelete()
- Model.findOneAndRemove()
- Model.findOneAndReplace()
- Model.findOneAndUpdate()
- Model.replaceOne()
- Model.updateMany()
- Model.updateOne()
Một mongoose query có thể đươc thực thi bằng hai cách. Trước tiên, nếu bạn muốn một sử callback fucntion thì Mongoose sẽ thực thi câu lệnh bằng các hàm bất đồng bộ và trả về callback. Một lệnh truy vấn (query) cũng có hàm .then()
, và sau đó bạn có thể sử dụng nó như là một promise.
2. Thực thi query
Khi bạn thực thi một query với một callback function, thực chất bạn đang chỉ định truy vấn như là một JSON document. Cú pháp của JSON document giống như trong MongoDB shell.
Bài viết này được đăng tại [free tuts .net]
var Person = mongoose.model('Person', yourSchema); // tìm một người với last name là Ghost, chọn các trường hiển thị là name, occupation Person.findOne({ 'name.last': 'Ghost' }, 'name occupation', function (err, person) { if (err) return handleError(err); // In ra "Space Ghost is a talk show host". console.log('%s %s is a %s.', person.name.first, person.name.last, person.occupation); });
Mongoose thực thi câu lệnh rồi trả kết quả về một callback function. Tất cả các callback mà mongoose trả về đều có các tham số callback(err, result).
Nếu trong quá trình truy vấn xảy ra lỗi, tham số error
sẽ chứa document lỗi và tham số result
sẽ trả về null
. và ngược lại.
Bất cứ khi nào một callback được gọi khi thực thi một query trong Mongoose, nó sẽ trả về kết quả trương ứng phụ thuộc vào mục đích mà bạn sử dụng.
Ví dụ như hàm findOne()
sẽ trả về một document duy nhất tìm được hoặc trả về null
nếu không tìm thấy, hay find()
sẽ trả về một list các documents liên quan, count()
trả về số document ảnh hưởng, update()
là số document đã được update,...Bạn có thể xem các API của Model để biết được callback trả về giá trị gì.
Một query có thể được xây dựng bằng một JSON doc hay bằng query builder, chúng ta có ví dụ bên dưới :
// With a JSON doc Person. find({ occupation: /host/, 'name.last': 'Ghost', age: { $gt: 17, $lt: 66 }, likes: { $in: ['vaporizing', 'talking'] } }). limit(10). sort({ occupation: -1 }). select({ name: 1, occupation: 1 }). exec(callback); // Using query builder Person. find({ occupation: /host/ }). where('name.last').equals('Ghost'). where('age').gt(17).lt(66). where('likes').in(['vaporizing', 'talking']). limit(10). sort('-occupation'). select('name occupation'). exec(callback);
Ngoài ra bạn có thể tìm hiểu thêm về các query helper bằng cách truy cập vào trang chỉ Mongoose API để xem : https://mongoosejs.com/docs/api.html#query-js
3. Queries không phải là Promises
Có một vài sự nhầm lẫn rằng các Queries là một promise bởi ví có phương thức then()
, thực chất Mongoose thêm phương thức này vào để thuận tiện cho khi làm việc với async/await. Khi sử dụng then()
trong một Queries chúng ta đang thực hiện 2 câu truy vấn : một là truy vấn thông thường sử dụng callback và hai là .then()
. Hơi mung lung nhưng chúng ta có ví dụ bên dưới để giải thích cụ thể hơn :
const q = MyModel.updateMany({}, { isDeleted: true }, function() { console.log('Update 1'); }); q.then(() => console.log('Update 2')); q.then(() => console.log('Update 3'));
Ví dụ bên trên chúng ta có thể thấy mỗi khi sử dụng .then()
thì document lại được update. Các bạn lưu ý khi sử dụng nó nhé ! Đừng sử dụng kết hợp giữa callback và then()
.
4. Thao tác với document khác
Trong khi làm việc với Mongoose, chúng ta không chỉ làm việc với một collection duy nhất mà phải thao tác giữa rất nhiều collections khác nhau. Chúng ta có thể liên kết với các document nằm trong collections khác bằng cách sử dụng populate
. Ở đây Mongoose cung cấp một vài thao tác làm việc với các document khác như :
Streaming
Đây là một tính năng khá hay cho phép bạn truy cập vào các câu truy vấn được thực thi để lấy dữ liệu, để làm điều này bạn càn gọi một Query#curson() :
var cursor = Person.find({ occupation: /host/ }).cursor(); cursor.on('data', function(doc) { // Được gọi ở bất cứ document nào }); cursor.on('close', function() { // Được gọi khi đã hoàn tất });
Versus Aggregation
Aggregation có thể làm những thứ mà Query có thể làm. Ví dụ bên dưới mình sử dụng aggregation
để tìm một document nơi mà có name.last = 'Ghost'
:
const docs = await Person.aggregate([{ $match: { 'name.last': 'Ghost' } }]);
Tuy nhiên, bạn chỉ nên sử dụng aggregate() khi bạn thực sự cần thiết.
Không giống như các query thông thường, kết quả trả về của một aggregation luôn luôn mà một POJOs (plain old javascript object), không phải là một Mongoose documents. Ở đây mình có ví dụ để so sánh:
const docs = await Person.aggregate([{ $match: { 'name.last': 'Ghost' } }]); docs[0] instanceof mongoose.Document; // false
Bởi vậy, khi chúng ta thực hiện các câu lệnh filter thì sử dụng aggregate()
sẽ xảy ra lỗi khi bạn truyền vào sai kiểu dữ liệu.
const doc = await Person.findOne(); const idString = doc._id.toString(); // Khi sử dụng Queries thì hàm sẽ tự chuyển kiểu dữ liệu của biến idString // từ string sang ObejctID một cách tự động. Quá trình này gọi là cast const queryRes = await Person.findOne({ _id: idString }); // Đối với aggreate thì không tự động cast mà dữ nguyên kiểu của idString // là String. Vậy nên câu lệnh này sẽ trả về lỗi. const aggRes = await Person.aggregate([{ $match: { _id: idString } }])
Xem thêm các API về Aggregation ở đây : https://mongoosejs.com/docs/api.html#aggregate_Aggregate
Trên đây là những kiến thức cơ bản về Create / Read / Update / Delete trong Mongoose. Mong bài viết này có thể giúp ích cho bạn cho việc lập trình với NodeJS, cảm ơn bạn đã quan tâm bài viết này.