CĂN BẢN
SERVER
MYSQL
MONGODB
MODULE
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
MỚI CẬP NHẬT

Populate trong Mongoose

Trong bài viết này chúng ta sẽ cùng nhau đi tìm hiểu về Populdate trong Mongoose.

Trong phiên bản từ 3.2 trở đi Mongose có hỗ trợ một aggregation operator hỗ trợ việc join các document có mối liên hệ với nhau là lockup. Nhưng phổ biến và mạnh mẽ hơn đó chính là populate(), cho phép bạn join các document từ các collections khác.

banquyen png
Bài viết này được đăng tại freetuts.net, không được copy dưới mọi hình thức.

Populate là quá quá trình tự động thay thế các paths trong documents gốc bằng cách documents trong các documents khác. Chúng ta có thể gộp một hay nhiều document, objects hay tất cả object từ một query. Bên dưới là ví dụ cụ thể:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const personSchema = Schema({
  _id: Schema.Types.ObjectId,
  name: String,
  age: Number,
  stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

const storySchema = Schema({
  author: { type: Schema.Types.ObjectId, ref: 'Person' },
  title: String,
  fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});

const Story = mongoose.model('Story', storySchema);
const Person = mongoose.model('Person', personSchema);

Bên trên chúng ta có đã khởi tạo 2 Models. Person sẽ có một trường lưu trữ stories là một array ObjectID. Thuộc tính ref được sử dụng để cho Mongoose biết rằng trường này được join đến model nào, trong trường hợp này là model Story. Tất cả _ids mà chúng ta lưu trữ phải là _ids của một document trong Story model.

Chú ý: ObjectId, Number, String, và Buffer đều sử dụng được options ref. Tuy nhiên bạn nên sử dụng ObjectID ngoại trư trường hợp đặc biệt.

1. Lưu một refs

Bên trên chúng ta đã khởi tạo 2 Model, bây giờ mình sẽ thêm vào Person một document và đồng nghĩa với nó mình cũng thêm một document trong Story.

const author = new Person({
  _id: new mongoose.Types.ObjectId(),
  name: 'Nguyễ  Du',
  age: 0
});

author.save(function (err) {
  if (err) return handleError(err);

  const story1 = new Story({
    title: 'Truyện Kiều',
    author: author._id    // Lấy giá trị của ._id cho refs
  });

  story1.save(function (err) {
    if (err) return handleError(err);
    //Lưu thành công !!!
  });
});

2. Population

Tiếp theo, sau khi thêm một refs bạn có thể thực hiện gộp documents trong Story vào Person quá trình này gọi là populate, cũng gần tương tự như join trong MySQL. Bên dưới mình có ví dụ cụ thể :

Story.
  findOne({ title: 'Truyện Kiều' }).
  populate('author').
  exec(function (err, story) {
    if (err) return handleError(err);
    console.log('Tác giả %s', story.author.name);
    // prints "Tác giả Nguyễn Du"
  });

Tùy chọn các trường

Chúng ta cũng có thể tùy chỉnh các trường được trả về để tiết kiệm tài nguyên, ví dụ bên dưới mình sẽ chỉ trả về giá trị author.name mà thôi.

Story.
  findOne({ title: 'Truyện Kiều' }).
  populate('author', 'name'). // Chỉ trả về Person name
  exec(function (err, story) {
    if (err) return handleError(err);

    console.log('Tác giả : %s', story.author.name);
    // prints "Tác giả : Nguyễn Du"

    console.log('Tuổi %s', story.author.age);
    // prints "Tuổi : null'
  });

Populate với nhiều Paths

Ngoài ra, chúng ta còn có thể populate với nhiều path khác nhau bằng cú pháp sau:

Story.
  find(...).
  populate('fans').
  populate('author').
  exec();

Thêm điều kiện truy vấn

Bạn có thể thêm điều kiện truy vấn, trong ví dụ trên mình sẽ truy vấn fans dựa vào tuổi lớn hơn 50:

Story.
  find(...).
  populate({
    path: 'fans',
    match: { age: { $gte: 50 } },
    select: 'name -_id'
  }).
  exec();

Ngoài ra populate còn hỗ trợ giới hạn các document, thêm object options như ví dụ:

const stories = Story.find().sort({ name: 1 }).populate({
  path: 'fans',
  options: { limit: 2 } //giới hạn các document
});

stories[0].fans.length; // 2
stories[1].fans.length; // 0

Nếu bạn muốn giới hạn trong mỗi document thì bạn có thể sử dụng perDocumentLimit :

const stories = await Story.find().sort({ name: 1 }).populate({
  path: 'fans',

  perDocumentLimit: 2
});

stories[0].fans.length; // 2
stories[1].fans.length; // 2

Populate với nhiều cấp

Ở đây mình có một Model như sau:

var userSchema = new Schema({
  name: String,
  friends: [{ type: ObjectId, ref: 'User' }]
});

Giả sử bạn muốn lấy tất cả bạn bè của một người nào đó, rồi lại lấy bạn bè của những người vừa lấy được =))) Chúng ta sẽ sử dụng cú pháp sau:

User.
  findOne({ name: 'Val' }).
  populate({
    path: 'friends',
    // Get friends of friends - populate the 'friends' array for every friend
    populate: { path: 'friends' }
  });

refPath

Mongoose cũng có thể populate từ nhiều collections khác nhau dựa trên giá trị của thuộc tính trong document. Giả sử bạn đang xây dựng một Schema để lưu trữ bình luận. Người dùng có thể comment về bài đăng trên Blog hoặc Sản phẩm

const commentSchema = new Schema({
  body: { type: String, required: true },
  on: {
    type: Schema.Types.ObjectId,
    required: true,
    refPath: 'onModel'
  },
  onModel: {
    type: String,
    required: true,
    enum: ['BlogPost', 'Product']
  }
});

const Product = mongoose.model('Product', new Schema({ name: String }));
const BlogPost = mongoose.model('BlogPost', new Schema({ title: String }));
const Comment = mongoose.model('Comment', commentSchema);

Lúc này khi lưu một comment bạn chỉ cần chọn Model mà bạn muốn dùng để populate :

const book = await Product.create({ name: 'Freetuts });
const post = await BlogPost.create({ title: 'Lập trình NodeJS' });

const commentOnBook = await Comment.create({
  body: 'Sách hay',
  on: book._id,
  onModel: 'Product'
});

const commentOnPost = await Comment.create({
  body: 'Thông tin rất hữu ích',
  on: post._id,
  onModel: 'BlogPost'
});

const comments = await Comment.find().populate('on').sort({ body: 1 });
comments[0].on.name; // "Freetuts"
comments[1].on.title; // "Lập trình NodeJS"

Populate trong Middleware

Tham khảo thêm bài viết về Middleware. Bạn có thể thực hiện thao tác populate trong pre và posts hooks. Chúng ta có một vài ví dụ :

// Thường dùng `populate()` khi `find()` được gọi
MySchema.pre('find', function() {
  this.populate('user');
});
// Thường gọi `populate()` sau khi `find()` được gọi. 
// Rât hữu ích trong trường hợp bạn muốn populate sau khi tìm được documents
MySchema.post('find', async function(docs) {
  for (let doc of docs) {
    if (doc.isPublic) {
      await doc.populate('user').execPopulate();
    }
  }
});
// `populate()` sau khi save. 
// Hưu ích cho việc gửi populate về API
MySchema.post('save', function(doc, next) {
  doc.populate('user').execPopulate().then(function() {
    next();
  });
});

Trên đây là những kiến thức cơ bản về Populate 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.

Cùng chuyên mục:

Crawl dữ liệu website bằng NodeJS cơ bản

Crawl dữ liệu website bằng NodeJS cơ bản

CORS là gì ? Xử lý CORS trong NodeJS

CORS là gì ? Xử lý CORS trong NodeJS

Chắc hẳn trong quá trình xử lý các request tới server thì một vài trường…

Xử lý form trong Express

Xử lý form trong Express

Xây dựng URL trong Express

Xây dựng URL trong Express

Trong bài viết này chúng ta sẽ cùng nhau đi tìm hiểu về cách xây…

Error Handling & Debugging trong Socket.io

Error Handling & Debugging trong Socket.io

Namespaces & Rooms trong Socket.io

Namespaces & Rooms trong Socket.io

Middleware trong Mongoose

Middleware trong Mongoose

Create / Read / Update / Delete trong Mongoose

Create / Read / Update / Delete trong Mongoose

Validation trong Mongoose

Validation trong Mongoose

Subdocuments trong Mongooose

Subdocuments trong Mongooose

Documents trong Mongoose

Documents trong Mongoose

Trong bài viết này chúng ta sẽ tìm hiểu về documents trong Mongoose

Models trong Mongoose

Models trong Mongoose

SchemaTypes trong Mongoose

SchemaTypes trong Mongoose

Schemas trong Mongoose

Schemas trong Mongoose

Mongoose trong NodeJS

Mongoose trong NodeJS

Làm việc với Table MySQL sử dụng Nodejs

Làm việc với Table MySQL sử dụng Nodejs

Kết nối với MongoDB trong NodeJS

Kết nối với MongoDB trong NodeJS

Giới thiệu MongoDB trong NodeJS

Giới thiệu MongoDB trong NodeJS

Insert / Update / Delete / Select MySQL trong NodeJS

Insert / Update / Delete / Select MySQL trong NodeJS

Broadcasting trong Socket.io

Broadcasting trong Socket.io

Top