Hướng dẫn lọc sản phẩm nodejs

How to Remove Array Duplicates in ES6. Có những câu hỏi tôi thường thấy trên những diễn đàn như reddit hay stackoverflow vấn đề làm sao để loại bỏ những phần tử trùng nhau trong array một cách nhanh gọn mà không làm code của bạn rối tung lên. Sau đây bài viết sẽ giúp bạn làm được điều đó với 6 cách loại bỏ phần tử trùng lặp.


1. Sử dụng thuộc tính indexOf của mảng để truy vấn


Bởi vì khi ES6 được giới thiệu thì lúc đó cũng có sự nhầm lẫn giữa FindIndex vs indexOf trong javascript. Chính vì lẽ đó nên nhớ sử dụng indexOf() khi tìm index của một array kiểu primitive types (like string, number, or boolean).


function unique(arr) {
  var newArr = []
  for (var i = 0; i < arr.length; i++) {
    if (newArr.indexOf(arr[i]) === -1) {
      newArr.push(arr[i])
    }
  }
  return newArr
}
console.log(unique([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]))

2. Sắp xếp mảng ban đầu trước, so sánh nó với các mảng liền kề và lưu trữ chúng trong mảng mới nếu chúng khác nhau.


Đây có thể gọi là một phương pháp lập trình theo tư duy, mỗi người có một cách để giải quyết.

function unique(arr) {
  var formArr = arr.sort()
  var newArr = [formArr[0]]
  for (let i = 1; i < formArr.length; i++) {
    if (formArr[i] !== formArr[i - 1]) {
      newArr.push(formArr[i])
    }
  }
  return newArr
}
console.log(unique([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]))

3. Sử dụng các đặc điểm hiện có của thuộc tính đối tượng và lưu trữ nó trong một mảng mới nếu không có thuộc tính đó.


function unique(arr) {
  var obj = {}
  var newArr = []
  for (let i = 0; i < arr.length; i++) {
    if (!obj[arr[i]]) {
      obj[arr[i]] = 1
      newArr.push(arr[i])
    }
  }
  return newArr
}
console.log(unique([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]))


4. Sử dụng includes()


function unique(arr) {
  var newArr = []
  for (var i = 0; i < arr.length; i++) {
    if (!newArr.includes(arr[i])) {
      newArr.push(arr[i])
    }
  }
  return newArr
}
console.log(unique([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]))


5. Sử dụng filter và includes

Tips: Cẩn thẩn khi sử dụng filter trong es6

function unique(arr) {
  var newArr = []
  newArr = arr.filter(function (item) {
    return newArr.includes(item) ? '' : newArr.push(item)
  })
  return newArr
}
console.log(unique([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]))


6. Sử dụng Set() của ES6.

Sự tiện dụng của map và set trong ES6 là một điều tuyệt vời khi ES mang lại cho mỗi lập trình javascript.

Ý tưởng cái này cũng đơn giản thôi thì như các bạn đã biết thì bây giờ mình sẽ tạo một trang page chứa chứa tất cả sản phẩm đúng không nào. Nhưng bây giờ nếu như chúng ta có 200 sản phẩm mà chỉ đặt chúng lên một trang thì đó không phải là cách tối ưu và trải nghiệm người dùng không được tốt. Nên chúng ta sẽ sử dụng kỹ thuật phân trang(pagination).

Hướng để làm cái thì mình bắt buộc phải có sản phẩm(data) gì đó rồi mới làm phân trang cho nó đúng không nào. Bây giờ mình muốn phân làm 4 trang mỗi trang 16 sản phẩm(data) thế là chúng ta cần phải tạo 64 sản phẩm à tạo khi nào cho xong nên ta cần phải fake data cho chúng =))

Bài này mình chỉ hướng dẫn các bạn làm về pagination nên mới fake data chớ vào thực tế thì các bạn phải tạo sản phẩm đầy đủ nha.
Sau khi mà fake data thì đây là bước quan trọng nhất đó là phân trang các bạn xem tiếp để biết thêm chi tiết nha. Đó cũng chính là ý tưởng của mình và bây giờ chúng ta sẽ biến ý tưởng thành hiện thực.

Hướng dẫn lọc sản phẩm nodejs

Cài Đặt Và Thiết Lập

Trước tiên các bạn tạo cho mình một folder trong folder đó là nơi chứa các thư mục dùng để mình code pagination.
Để mà cài các module trước hết các bạn phải cài đặt NodeJS tại đây.
Khởi tạo ứng dụng với file package.json
Trong thư mục gốc của ứng dụng của bạn và nhập

router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
0 để khởi tạo ứng dụng của bạn với tệp package.json.
router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
0
Sau đó các bạn cài đặt các module ở dưới để thiết lập ứng dụng nha.

  • npm install express --save
    Module dùng để cài đặt framework express của nodejs giúp các bạn code một cách tối giản cũng như nhanh chóng hơn.
  • npm install nodemon --save
    Tự động reload lại server khi bạn thay đổi code. Để khởi chạy server các bạn thêm
    router.get('/', (req, res, next) => {
       res.send('Hello Everyone')
    })
    
    2 vào file package.json nha. Các bạn mở terminal lên sau đó gõ
    router.get('/', (req, res, next) => {
       res.send('Hello Everyone')
    })
    
    3 để khởi chạy server nha.
  • npm install mongoose --save
    Mongoose là một Object Document Mapper (ODM). Điều này có nghĩa là Mongoose cho phép bạn định nghĩa các object (đối tượng) với một schema được định nghĩa rõ ràng.
  • npm install dotenv --save
    Dotenv là một biến môi trường dùng để bảo mật các thông tin quan trọng như username, password, url database,...Nếu chúng ta không lưu những thông tin mật vào file .env thì khi push source code lên github thì ai cũng có thể vào xem được và ai cũng biết username, password thì sẽ bị người khác chiếm đoạt và đánh cắp tài liệu rất là nguy hiểm nha.
  • npm install faker --save
    Faker là một package dùng để tạo các dữ liệu fake(giả) bao gồm rất nhiều API methods khác nhau như address, image, name,... các bạn xem thêm
  • npm install ejs --save
    EJS nó chỉ là một template engine mà thôi hôm nay mình đổi giớ một tí thay vì dùng pug thì mình dùng ejs.
    Và đây cũng là các package mà mình khi đã cài đặt cũng như cấu hình xong.
Hướng dẫn lọc sản phẩm nodejs

Cấu Trúc Thư Mục Cho Dự Án

Sau khi hoàn thành việc cài đặt module các bạn tạo cho mình một thư mục

router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
4, thư mục này dùng để chứa tất cả các file trong quá trình mình code project.
Mình khuyên các bạn nên tạo thêm một folder controllers và file để chứa các logic khi mình code. Do mình code để làm demo cho mọi người nên mình viết chung vào thằng routes luôn.

Hướng dẫn lọc sản phẩm nodejs

Bắt Đầu Code Thôi Nào

Thiết Lập Web Server

Trong thư mục gốc các bạn tạo cho mình file app.js, file này là file chính dùng để điều khiển mọi hoạt động chính của server.

const express = require("express")
const app = express()
const path = require("path")
const port = 3333

// Import routes
const indexRoutes = require("./routes/index.routes")

// Settings
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');


// routes
app.use(indexRoutes);

app.listen(port, function(){
    console.log(`Server listening ${port}`)
})

Trong thư mục

router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
5 có file
router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
6, các bạn tạo cho nó một Route handlers và thử chạy sever xem sau. Mục đích để các bạn test xem server có chạy không nha.

router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
Hướng dẫn lọc sản phẩm nodejs

Thiết Lập Database

Để mà có thể thiết lập được database thì các bạn đăng nhập tài khoản mongodb atlas tại đây nha. Sau khi các bạn bạn đã có tài khoản mongodb atlas thì tiếp đến cài đặt cấu hình để có thể kết nối mongodb atlas với ứng dụng của chúng ta. Để biết thêm chi tiết các bạn xem bước 3 trong bài viết của mình hướng dẫn deploy project nodejs lên heroku tại đây nha.
Sau đó các bạn copy link database mongodb đã tạo rồi paste vào project của mình là được nha. Các bạn tạo cho mình một file

router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
7 bên trong thư mục gốc.
Trong file này các bạn tạo một đường dẫn là
router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
8
Trong file app.js các bạn khai báo module dotenv với module mongoose và tạo đường dẫn mongodb.
// Khai báo dotenv
router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
9
// Khai báo mongoose
// Connect database
mongoose.connect(process.env.DATABASE_URL, 
    {useNewUrlParser: true, useUnifiedTopology: true}).then(function() {
        console.log("Successfully connected to the database");    
    }).catch(function(err) {
        console.log('Could not connect to the database. Exiting now...', err);
        process.exit();
    });
0

// Connect database
mongoose.connect(process.env.DATABASE_URL, 
    {useNewUrlParser: true, useUnifiedTopology: true}).then(function() {
        console.log("Successfully connected to the database");    
    }).catch(function(err) {
        console.log('Could not connect to the database. Exiting now...', err);
        process.exit();
    });

Để biết nó đã kết nối hay chưa các bạn khởi động lại server sẽ biết nha.

Hướng dẫn lọc sản phẩm nodejs

Thiết Kế Giao Diện

Nói thiết kế thì nó hơi quá chớ thật ra làm cái này cũng đơn giản. Không cần làm mà vẫn có ăn^^, đùa chút thôi nha. Trước tiên mình sẽ code giao diện trang chủ như các bạn đã thấy ở trên phần cấu trúc thư mục thì ta thấy trong folder

// Connect database
mongoose.connect(process.env.DATABASE_URL, 
    {useNewUrlParser: true, useUnifiedTopology: true}).then(function() {
        console.log("Successfully connected to the database");    
    }).catch(function(err) {
        console.log('Could not connect to the database. Exiting now...', err);
        process.exit();
    });
1 chứa folder layout chứa các file như: header.ejs, footer.ejs là nơi mà chúng ta dùng để code giao diện cho app. Mình sử dụng template engine ejs nên nó khá quen thuộc với chúng ta bởi vì nó khá giống html thuần.
Trong file header.ejs mình sẽ tạo cho nó một thanh nav sẽ bao gồm logo và menu. Và trong menu sẽ chữa một nav link đó là Fake data product để khi chúng ta click vào đó sẽ tạo các data fake cái này mình sẽ nói rõ ở phần sau bạn không cần quan tâm quá nhiều.





  
  
  Pagination
  




  
  
  

Và đây là giao diện cho trang chủ của chúng ta

Hướng dẫn lọc sản phẩm nodejs

Định Nghĩa Các Schema Product Cho Mongoose

Như các bạn đã đọc ở trên thì cấu trúc thư mục cho dự án bên trong thư mục

router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
4 các bạn tạo cho mình thư mục
// Connect database
mongoose.connect(process.env.DATABASE_URL, 
    {useNewUrlParser: true, useUnifiedTopology: true}).then(function() {
        console.log("Successfully connected to the database");    
    }).catch(function(err) {
        console.log('Could not connect to the database. Exiting now...', err);
        process.exit();
    });
3, bên trong thư mục
// Connect database
mongoose.connect(process.env.DATABASE_URL, 
    {useNewUrlParser: true, useUnifiedTopology: true}).then(function() {
        console.log("Successfully connected to the database");    
    }).catch(function(err) {
        console.log('Could not connect to the database. Exiting now...', err);
        process.exit();
    });
3 các bạn tạo cho mình file
// Connect database
mongoose.connect(process.env.DATABASE_URL, 
    {useNewUrlParser: true, useUnifiedTopology: true}).then(function() {
        console.log("Successfully connected to the database");    
    }).catch(function(err) {
        console.log('Could not connect to the database. Exiting now...', err);
        process.exit();
    });
5.
Trong file
// Connect database
mongoose.connect(process.env.DATABASE_URL, 
    {useNewUrlParser: true, useUnifiedTopology: true}).then(function() {
        console.log("Successfully connected to the database");    
    }).catch(function(err) {
        console.log('Could not connect to the database. Exiting now...', err);
        process.exit();
    });
5 cần tạo một đối tượng book và sẽ chứa ba fields là name, price và cover.

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

const productSchema = new Schema({
    name: {type: String, required: true},
    price: {type: Number, required: true},
    cover: {type: String, required: true}
})
// Biên dịch mô hình từ schema
module.exports =  mongoose.model('product', productSchema)

Tham số thứ nhất là tên riêng cho collection sắp được tạo ra cho mô hình của bạn, và tham số thứ hai là schema mà bạn muốn dùng để tạo ra mô hình.
Sau khi chúng ta đã setup xong hệ thống thì bây giờ mình sẽ đi đến chức năng là tạo data fake và lưu vào DB như mong muốn của mình.

Tạo Dữ Liệu Fake

Nhìn tiêu đề hơi củ chuối các ông nhờ =)). Nhưng mà không sao củ chuối nhiều lúc cũng thú vị, mình không có đi vòng vo nữa mà là vào thẳng vẫn đề chính luôn đó là tạo data giả(fake). Lý do tại sao chúng ta lại phải fake data mục đích của nó đơn giản là có tạo ra nhiều data một cách nhanh chóng để thực hiện công việc đó là phân trang(pagination).
Trong thư mục

router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
4 các bạn tạo cho mình thư mục
router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
5, bên trong thư mục
router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
5 các bạn tạo cho mình file
router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
6.
Trong file
router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
6 các bạn cần import và khai báo một số module như model, faker,...
Tiếp đến bạn tạo cho mình một




  
  
  Pagination
  




  
  
  
2 để khi chúng ta click vào router đó nó sẽ tự động tạo cho ta hàng loạt các data fake và lưu vào database như ta mong muốn.
Mình sẽ giải thích qua một chút đó là chúng ta tạo một vòng lặp để làm gì để nó có thể tự động tạo số lượng data mà mình muốn fake. Trong vòng lặp đó tạo một object empty để chứa các thuộc tính của một sản phẩm như name, price, coverImg và lưu vào database rồi redirect trang chủ. Còn các API để tạo dữ liệu fake các bạn xem nó cũng khá là đơn giản.

const express = require("express")
const router = express.Router()
const faker = require('faker');
const Product = require("../models/product.model")

.............
.............
.............
  // Fake data products
router.get('/generate-fake-data', async(req, res, next) =>{
    for(let i = 0; i < 96; i++) {
    const newprd = new Product();
    newprd.name = faker.commerce.productName()
    newprd.price = faker.commerce.price()
    newprd.cover = faker.image.image()
    
    newprd.save((err)=>{
        if (err) { return next(err); }
      });
    }
    res.redirect('/');    
}) 

............
............
............

module.exports = router

Chúng ta cùng xem thử kết quả để biết nó có tự động fake data và lưu vào DB không nha

Hướng dẫn lọc sản phẩm nodejs

Hướng Dẫn Phân Trang

Sau khi đã data fake xong bây giờ chúng ta sẽ bắt đầu phân trang cho nó nha. Để phân trang mình cần làm như nhờ =)) mình sẽ nói sơ qua chút về quy trình hoạt động nha.
Thì khi chúng ta đã fake dữ liệu cho nó xong thì công việc bây giờ chính là phân trang. Có rất nhiều cách để phân trang nhưng mình sẽ sử dụng





  
  
  Pagination
  




  
  
  
3 và sử dụng nó như thế nào thì các bạn xem tiếp nha.
Mục đích khi mình sử dụng




  
  
  Pagination
  




  
  
  
3 đó là lấy thông số các page.
VD: router.get('/news/:page', (req, res, next) => {} ) thì page được gọi là params ngoài các này các bạn cũng có thể sử dụng




  
  
  Pagination
  




  
  
  
5 để truy vấn vào các trang được pagination.
Code Thôi Nào
Trong quá trình code mình sẽ nói thêm cho các bạn dễ hiểu hơn.
Bên trong thư mục routes có file
router.get('/', (req, res, next) => {
   res.send('Hello Everyone')
})
6 chúng ta sẽ tạo một




  
  
  Pagination
  




  
  
  
7

// pagination
router.get('/news/:page', (req, res, next) => {
    let perPage = 16; // số lượng sản phẩm xuất hiện trên 1 page
    let page = req.params.page || 1; 
  
    Product
      .find() // find tất cả các data
      .skip((perPage * page) - perPage) // Trong page đầu tiên sẽ bỏ qua giá trị là 0
      .limit(perPage)
      .exec((err, products) => {
        Product.countDocuments((err, count) => { // đếm để tính có bao nhiêu trang
          if (err) return next(err);
           res.send(products) // Trả về dữ liệu các sản phẩm theo định dạng như JSON, XML,...
        });
      });
  });

Và đây là kết quả khi chúng ta truy cập url





  
  
  Pagination
  




  
  
  
8 thì nó sẽ trả về dữ liệu các sản phẩm xuất hiện trên một trang đây là mình chỉ test thử thôi nha.
Hướng dẫn lọc sản phẩm nodejs

Sau khi chúng ta đã test thành công bằng cách gửi dữ liệu về, bây giờ ta cần làm là biến chúng thành những giao diện đẹp mắt =))
Thay vì





  
  
  Pagination
  




  
  
  
9 để trả về dữ liệu theo dạng json thì bây giờ chúng ta sẽ thay đổi thành
const mongoose = require("mongoose")
const Schema = mongoose.Schema;

const productSchema = new Schema({
    name: {type: String, required: true},
    price: {type: Number, required: true},
    cover: {type: String, required: true}
})
// Biên dịch mô hình từ schema
module.exports =  mongoose.model('product', productSchema)
0 để trả về dữ liệu dưới dạng html nha.

// pagination
router.get('/news/:page', (req, res, next) => {

     .............
     .............
     .............
          res.render('product/index_product', {
            products, // sản phẩm trên một page
            current: page, // page hiện tại
            pages: Math.ceil(count / perPage) // tổng số các page
          });
          
      ..............
      ..............
      ..............

Trong file

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

const productSchema = new Schema({
    name: {type: String, required: true},
    price: {type: Number, required: true},
    cover: {type: String, required: true}
})
// Biên dịch mô hình từ schema
module.exports =  mongoose.model('product', productSchema)
1 ta sẽ code giao diện pagination cho nó. Trước tiên mình sẽ phải include thằng header và footer vào cái đã, để mà có thể hiển thị được sản phẩm ta chỉ cần lặp qua rồi chia cột cho nó là được. Nếu muốn hiển thị 3 sản phẩm thì col-4 còn muốn hiển thị 4 sản phẩm thì col-3 có thể thôi ấy mà :))

Tiếp đến phần khá là quan trọng đó là phân trang

<%- include('../layout/header'); -%>


<% for(var i = 0; i < products.length; i++) { %>

<%= products[i].name %>

<%= products[i].category %>

<%= products[i].price %>$

<% } %>
<% if(pages > 0) { %> <% } %>
<%- include('../layout/footer'); -%>

Và đây là kết quả khi chúng ta đã hoàn thành pagination cho nó:))

Hướng dẫn lọc sản phẩm nodejs

Từ từ mọi người đừng mừng vội còn một việc nữa đó là chả lẻ giờ muốn xem pagination thì phải ghi params

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

const productSchema = new Schema({
    name: {type: String, required: true},
    price: {type: Number, required: true},
    cover: {type: String, required: true}
})
// Biên dịch mô hình từ schema
module.exports =  mongoose.model('product', productSchema)
2 vào url như này
const mongoose = require("mongoose")
const Schema = mongoose.Schema;

const productSchema = new Schema({
    name: {type: String, required: true},
    price: {type: Number, required: true},
    cover: {type: String, required: true}
})
// Biên dịch mô hình từ schema
module.exports =  mongoose.model('product', productSchema)
3 nhìn là biết trải nghiệm người dùng không tốt rồi =))
Bây giờ mình sẽ chuyển pagination ra trang home khi người dùng vào là sẽ thấy xuất hiện phân trang luôn. Đơn giản thôi bây giờ cũng trong file index.rotes.js bạn chỉ cần copy nguyên code từ
const mongoose = require("mongoose")
const Schema = mongoose.Schema;

const productSchema = new Schema({
    name: {type: String, required: true},
    price: {type: Number, required: true},
    cover: {type: String, required: true}
})
// Biên dịch mô hình từ schema
module.exports =  mongoose.model('product', productSchema)
4 sang
const mongoose = require("mongoose")
const Schema = mongoose.Schema;

const productSchema = new Schema({
    name: {type: String, required: true},
    price: {type: Number, required: true},
    cover: {type: String, required: true}
})
// Biên dịch mô hình từ schema
module.exports =  mongoose.model('product', productSchema)
5 là được thôi mà.

// home page
router.get('/', (req, res, next)=>{
  let perPage = 16; // số lượng sản phẩm xuất hiện trên 1 page
  let page = req.params.page || 1; 

  Product
    .find() // find tất cả các data
    .skip((perPage * page) - perPage) // Trong page đầu tiên sẽ bỏ qua giá trị là 0
    .limit(perPage)
    .exec((err, products) => {
      Product.countDocuments((err, count) => { // đếm để tính xem có bao nhiêu trang
        if (err) return next(err);
        res.render('product/index_product', {
          products, // sản phẩm trên một page
          current: page, // page hiện tại
          pages: Math.ceil(count / perPage) // tổng số các page
        });
      });
    });
})

Và đây là kết quả khi chúng ta chuyển pagination ra ngoài home page nha:

Hướng dẫn lọc sản phẩm nodejs

Vậy là xong rồi nha, các bạn có thể tham khảo code mà mình đã push lên github tại đây nha.

Lời Kết

Vậy Là Xong bài Hướng Dẫn Xây Dựng Pagination Với NodeJS, Express và MongoDB rồi nhé. Mình mong muốn sau bài topic này các bạn có thể biết và hiểu thêm về nodejs, express và biết pagination là gì?, từ topic này các bạn có thể mở rộng thêm ý tưởng và cách làm mới. Có thể tự tay mình làm những project không cần phải quá đặc biệt nhưng nó do chính bạn làm thì cũng coi như là thành quả trong quá trình bạn học được.