Seeder và faker để tạo dữ liệu mẫu cho MongoDB / Nodejs
Lấy 200$ cloud miễn phí để tha hồ deploy project và nghịch phá server ở đây nhé mọi người.
👇️👇️👇️
I. Giới thiệu
Lần trước mình có viết một bài hướng dẫn tạo đa ngôn ngữ cho ứng dụng web nodejs đa ngôn ngữ cho ứng dụng web nodejs, cũng được một bạn vào comment cám ơn - vui quá trời.. Hehe. Tại đây là lần đầu tiên mình viết bài trên viblo, cũng là lần đâu tiên chia sẽ một cái gì đó.. Nên n phấn khởi hơn bình thường
Nay mình xin mạo muộn chia sẻ thêm việc tạo dữ liệu mẫu trong ứng dụng nodejs. Nếu mn đã dùng qua laravel
hẳn đều biết đến việc tạo dữ liệu mẫu dùng seeder
và faker
, sau đó chỉ cần chạy lệnh php artiasan db:seed
là ra bao nhiêu dữ liệu tùy ý, tha hồ truy vấn thử mà không cần nhập dữ liệu mẫu một cách thủ công. Nay mình xin hướng dẫn các bạn cũng làm được như vậy cho ứng dụng nodejs dùng mongodb.... Chỉ với một lệnh node db_seed
là có thể tạo ra dữ liệu mẫu ở các collection mong muốn...
II. Tạo một project
Mình vẫn sẽ dùng express-generator
để tạo nhanh một project nhé:
- Nếu bạn chưa có
express-generator
: Gõ npm install express-generator -g Để cài đặt express-generator ở chế độ global. - Sau đó chuyển vào thư mục bạn muốn lưu project:
Gõ
express --view=ejs yourapp
để tạo mộtproject
mới với tên làyourapp
. Mình dùng view-engine làejs
nên mình để là--view=ejs
nếu bạn dùngjade
haypug
..v.v. thì sửa tham số nhé... - Sau đó, bạn sẽ được một project như dưới đây :
III. Nodejs seeder và faker
Để tạo dữ liệu mẫu, mình dùng hai package là mongoose-seed
và faker
. Bạn gõ npm install mongoose-seed --save
và npm install faker --save
để tải và lưu hai package này vào project của mình...
Sau đó trong project của bạn, tạo thêm thư mục model
, database
và thư mục con seeder
( Cho nó chuyên nghiệp. Hehe ). trong model bạn dùng mongoose
để định nghĩa các schema tương ứng cho các collection của bạn nhé. Ví dụ như mình có một schema Category
như sau, ví dụ thôi nhé :
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var CategorySchema = new mongoose.Schema({
name : String,
descript : String,
type : Number,
createdOn: { type: Date, 'default': Date.now }
});
module.exports = mongoose.model('Category', CategorySchema);
Xong công đoạn chuẩn bị râu ria rồi nè. Giờ giả dụ bạn cần seed dữ liệu cho collection category trên chẳng hạn. Ví dụ mình sẽ seed 15
mẫu dữ liệu nhé :
const seeder = require('mongoose-seed');
const faker = require('faker');
let items = [];
for(i=0; i < 15; i++){
items.push(
{
name : faker.commerce.productName(),
descript : faker.lorem.text(),
type : faker.random.number()
}
)
}
let data = [{
'model': 'Category',
'documents': items
}]
// connect mongodb
seeder.connect('mongodb://localhost:27017/havana', function() {
seeder.loadModels([
'../../model/category' // load mongoose model
]);
seeder.clearModels(['Category'], function() {
seeder.populateModels(data, function() {
seeder.disconnect();
});
});
});
Xong, bây giờ bạn chỉ cần chuyển terminal đến thư mục chứa file category_seeder này và chạy lệnh node category_seeder
là đã có thể thấy 15 mẫu dữ liệu được tạo trong categories collection như dưới đây :
IV. Dữ liệu có quan hệ reference
Đến đây bạn có thể thắc mắc rằng seed kiểu này thì đơn giản vấn đề là giữa các collection có quan hệ reference thì phải làm sao để lấy được ObjectId của document mà n tham chiếu đến để còn truy vấn thử ? Với cả nhỡ có nhiều collection thì phải chạy từng file à ? Và mình đã mất mất cả buổi chiều để giải quyết chuyện này... Ví dụ mình có Bill schema như sau :
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var BillSchema = new mongoose.Schema({
total : Number,
status : Number,
note: String,
address : String,
phone: String,
user_id : { type: ObjectId, ref : 'User'},
detais : [
{
product_id : { type: ObjectId, ref : 'Product'},
product_name : String,
price : Number,
quantity : Number
}
],
createdOn: { type: Date, 'default': Date.now }
});
module.exports = mongoose.model('Bill', BillSchema);
Như bạn có thể thấy, Bill
có quan hệ reference
với User
và Product
vấn đề là chúng ta làm sao lấy và sinh ngẫu nhiên được ObjectId
của thằng User
và Product
? Và đây là giải pháp của cá nhân
mình, truy vấn ra ObjectId của User và Product, ta có được hai mảng chứa object id của User và của Product... Sau đó dùng Lodash
để lấy ngẫu nhiêu các phần tử trong hai mảng này. Đại khái code như dưới đây :
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
const seeder = require('mongoose-seed');
const async = require('async');
const Product = require('../../model/product');
const User = require('../../model/user');
const _ = require('lodash');
var faker = require('faker');
new Promise((resolve) => {
mongoose.connect('mongodb://localhost:27017/havana', {
useMongoClient: true,
promiseLibrary: require('bluebird')
});
async.parallel([
(callback) => {
Product.find({}, { _id : 1 })
.exec((err, product_ids) => {
callback(null, product_ids);
});
},
(callback) => {
User.find({})
.exec((err, user_ids) => {
callback(null, user_ids);
});
}
],
(err, results) => {
resolve(results);
mongoose.connection.close();
});
}).then((results) => {
return new Promise((resolve) => {
let items = [];
let status = [1, 2]
for(i=0; i< 150; i++){
items.push(
{
total : faker.commerce.price(),
status : _.sample(status),
note: faker.lorem.text(),
address : faker.address.streetAddress,
phone: faker.phone.phoneNumber,
user_id : _.sample(results[0])._id,
detais : [
{
product_id : _.sample(results[1])._id,
product_name : _.sample(results[1]).name,
price : _.sample(results[1]).unit_price,
quantity : faker.random.number()
},
{
product_id : _.sample(results[1])._id,
product_name : _.sample(results[1]).name,
price : _.sample(results[1]).unit_price,
quantity : faker.random.number()
}
]
}
);
}
resolve(items);
});
}).then((items) => {
seeder.connect('mongodb://localhost:27017/havana', function() {
let data = [{
'model': 'Bill',
'documents': items
}]
seeder.loadModels([
'../../model/bill'
]);
seeder.clearModels(['Bill'], function() {
seeder.populateModels(data, function() {
seeder.disconnect();
});
});
});
});
V. Chạy nhiều seeder bằng một lệnh.
Cái này chỉ còn là việc tạo một module nhỏ rồi require các file seeder đã viết ở trên và chạy chúng thôi không có gì đặc biệt cả. Điều cần lưu ý là bạn nên để seeder nào chạy trước cái nào chaỵ sau. Ví dụ như Product chứa ObjectId của Category thì ta để category_seeder chạy trước, product_seeder chạy sau. Ở đây mình dùng asyn await
để chạy chúng tho thứ tự, ví dụ đây sẽ là file db_seed.js
:
const bill = require('./bill_seeder');
const category = require('./category_seeder');
const product = require('./product_seeder');
const user = require('./user_seeder');
async function dbseed() {
await category();
await product();
await user();
await bill();
console.log('data generate successfull');
}
Giờ thì thay vì chạy node abc để chạy từng file seeder, babnj chỉ cần chạy một file db_seed này với câu lệnh node db_seed
là đã có thê seed hêt các file dữ liệu mong muốn.
VI. Kết luận.
Vừa xong mình vừa tạo một module nhỏ, nhằm giúp bản thân có thể tiết kiện thời gian trong quá trình thiết kế và thử nghệm database. Vì mình cũng mới bập bõm dùng mongodb, nên cứ đập đi xây lại miết... Mà cứ mỗi lần như vậy lại phải chèn thêm ít dữ liệu để thử truy vấn thử lại, ấm ức quá trời. Nên mới tìm cách và mạo muộn chia sẽ lại cho mọi người, hy vọng nhận được sự góp ý cũng như chỉ dẫn cách khác tốt hơn nếu có...
Để xem rõ hơn các bạn vào xem ducoment của Mongoose-seed
tại đây
Còn Faker.js
tại đây
All rights reserved