Sử dụng Mongoose hay MongoDB tốt hơn?

Đã đến lúc đưa trình điều khiển gốc và cầy mangut vào thử nghiệm và đánh giá hiệu suất của từng người

Mongoose hỗ trợ rất nhiều cho MongoDB và cung cấp rất nhiều tính năng hữu ích trong Node. Đối với mã nhạy cảm với hiệu suất, đây có phải là lựa chọn tốt nhất không?

Cài đặt

Chúng tôi sẽ sử dụng Express để làm cho điểm chuẩn thực tế hơn một chút vì đây là một trong những điểm chuẩn nhanh nhất. Chỉ mã có liên quan sẽ được đăng nhưng vui lòng kiểm tra toàn bộ repo trên GitHub

Với trình điều khiển riêng, điểm cuối POST này tạo một tài nguyên mới

nativeApp.post('/', async (req, res) => {
  const data = await req.db.native.insertOne({
    number: req.body.number,
    lastUpdated: new Date()
  })
  res.set('Location', '/' + data.ops[0]._id)
  res.status(201).send(data.ops[0])
})

Lưu ý rằng có sẵn một đối tượng

nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})
2, liên kết với một bộ sưu tập cơ sở dữ liệu gốc

nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})

Hàm

nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})
3 này là phần mềm trung gian trong Express. Hãy nhớ điều này chặn mọi yêu cầu và nối cơ sở dữ liệu với đối tượng
nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})
4

Đối với Mongoose, chúng tôi có phần mềm trung gian tương tự thực hiện điều này

mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})

Lưu ý việc sử dụng

nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})
5 xác định các trường riêng lẻ trong bộ sưu tập. Nếu bạn đến từ SQL, hãy coi bảng là tập hợp và cột là trường

Điểm cuối POST cho Mongoose trông như thế này

mongooseApp.post('/', async (req, res) => {
  const data = await req.db.mongoose.create({
    number: req.body.number,
    lastUpdated: new Date()
  })
  res.set('Location', '/' + data.id)
  res.status(201).send(data)
})

Điểm cuối này sử dụng mã trạng thái HTTP kiểu REST của năm 201 để phản hồi với tài nguyên mới. Bạn cũng nên đặt tiêu đề

nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})
6 với URL và id. Điều này làm cho các yêu cầu tiếp theo đối với tài liệu này dễ dàng tìm thấy hơn

Để loại bỏ hoàn toàn MongoDB khỏi các điểm chuẩn này, hãy đảm bảo đặt

nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})
7 thành 1 trong đối tượng kết nối. Điều này làm cho cơ sở dữ liệu kém hiệu quả hơn nhưng lại gây thêm áp lực cho chính API. Mục tiêu không phải là đánh giá cơ sở dữ liệu mà là API và sử dụng các chiến lược khác nhau trong lớp dữ liệu

Để kích hoạt các yêu cầu tới API này, hãy sử dụng CURL và một cổng riêng cho từng chiến lược

curl -i -H "Content-Type:application/json" -d "{\"number\":42}" http://localhost:3001/
curl -i -H "Content-Type:application/json" -d "{\"number\":42}" http://localhost:3002/

Từ thời điểm này trở đi, giả sử cổng

nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})
8 có chiến lược trình điều khiển gốc. Cổng
nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})
9 dành cho chiến lược truy cập dữ liệu Mongoose

Đọc hiệu suất

Trình điều khiển gốc có điểm cuối GET sau

nativeApp.get('/:id', async (req, res) => {
  const doc = await req.db.native.findOne({_id: new ObjectId(req.params.id)})
  res.send(doc)
})

Đối với Mongoose, đây là một tài liệu duy nhất

mongooseApp.get('/:id', async (req, res) => {
  const doc = await req.db.mongoose.findById(req.params.id).lean()
  res.send(doc)
})

Lưu ý mã trong Mongoose dễ làm việc hơn. Chúng tôi đặt

mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
0 ở cuối truy vấn để làm cho điều này hiệu quả nhất có thể. Điều này ngăn Mongoose hydrat hóa toàn bộ mô hình đối tượng vì nó không cần chức năng này. Để có được phép đo hiệu suất tốt, hãy thử đo điểm chuẩn có và không có tùy chọn tinh gọn trong truy vấn

Để gửi yêu cầu tới cả hai điểm cuối trong Apache Benchmark

ab -n 150 -c 4 -H "Content-Type:application/json" http://localhost:3001/5fa548f96a69652a4c80e70d
ab -n 150 -c 4 -H "Content-Type:application/json" http://localhost:3002/5fa5492d6a69652a4c80e70e

Một vài đối số

mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
1 cần lưu ý. tham số
mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
2 là số lượng yêu cầu và
mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
3 là số lượng yêu cầu đồng thời. Trên hộp dành cho nhà phát triển có kích thước phù hợp, bạn sẽ thấy rằng nó có khoảng 8 lõi logic. Đặt số đếm đồng thời thành 4 sẽ chiếm một nửa số lõi và giải phóng tài nguyên cho API, cơ sở dữ liệu và các chương trình khác. Đặt số lượng đồng thời này thành một số cao có nghĩa là nó đang đo điểm chuẩn cho bộ lập lịch không đồng bộ trong CPU, do đó, kết quả có thể không thuyết phục

Viết hiệu suất

Đối với Mongoose, hãy tạo điểm cuối PUT cập nhật một tài liệu

mongooseApp.put('/:id', async (req, res) => {
  const { number } = req.body
  const data = await req.db.mongoose.findById(req.params.id)
  data.number = number
  data.lastUpdated = new Date()
  res.send(await data.save())
})

Trình điều khiển bản địa có thể làm điều này ngắn gọn

nativeApp.put('/:id', async (req, res) => {
  const { number } = req.body
  const data = await req.db.native.findOneAndUpdate(
    {_id: new ObjectId(req.params.id)},
    {$set: {number: number}, $currentDate: {lastUpdated: true}},
    {returnOriginal: false})
  res.send(data.value)
})

Mongoose có một phương pháp tương tự

mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
4 ít tốn kém hơn nhưng cũng ít tính năng hơn. Khi thực hiện điểm chuẩn, tốt hơn hết là bạn nên tuân theo các tình huống xấu hơn. Điều này có nghĩa là bao gồm tất cả các tính năng có sẵn để đưa ra quyết định sáng suốt hơn. Thực hiện
mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
5 sau đó là
mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
6 trong Mongoose đi kèm với tính năng theo dõi thay đổi và các tính năng mong muốn khác không có sẵn trong trình điều khiển gốc

Để đánh giá các điểm cuối này trong Apache Benchmark

nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})
0

Đảm bảo tạo một tệp

mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
7 với nội dung sau

nativeApp.use((req, res, next) => {
  req.db = {}
  req.db.native= nativeApp.get('db').collection('native')
  next()
})
1

Cả hai điểm cuối cập nhật trường dấu thời gian

mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
8 trong tài liệu. Điều này là để phá vỡ mọi bộ đệm Mongoose/MongoDB để tối ưu hóa hiệu suất. Điều này buộc cơ sở dữ liệu và lớp truy cập dữ liệu thực hiện công việc thực tế

Kết quả và Kết luận

Vui lòng đánh trống, dưới đây là kết quả

READSNativeMongooseThroughput1200 #/sec583 #/secAvg Request0. 83 ms1. 71 msWRITESNativeMongooseThroughput1128 #/sec384 #/secAvg Request0. 89 ms2. 60 mili giây

Nhìn chung, trình điều khiển bản địa nhanh hơn khoảng 2 lần so với Mongoose. Bởi vì trình điều khiển bản địa sử dụng

mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
4, đọc và ghi kết quả là giống hệt nhau.
mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
4 trong Mongoose hoạt động giống như
mongooseApp.post('/', async (req, res) => {
  const data = await req.db.mongoose.create({
    number: req.body.number,
    lastUpdated: new Date()
  })
  res.set('Location', '/' + data.id)
  res.status(201).send(data)
})
1 với tùy chọn
mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
0. Mongoose có một chút tiếng vang với
mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
6 nhưng điều này đi kèm với nhiều tính năng hơn. Loại bỏ
mongooseApp.use((req, res, next) => {
  req.db = {mongoose: mongooseConn.model(
    'Mongoose',
    new Schema({number: Number, lastUpdated: Date}),
    'mongoose')}
  next()
})
0 để ngăn hydrat hóa không tạo ra sự khác biệt vì đối tượng tài liệu nhỏ

Với những kết quả này, một điều rút ra là hãy chú ý đến hiệu suất khi chọn sử dụng Mongoose. Không có lý do thực sự nào để loại trừ trình điều khiển gốc khỏi Mongoose vì chúng cũng đồng thời hữu ích. Đối với mã nhạy cảm với hiệu suất, tốt nhất là sử dụng trình điều khiển gốc. Đối với các điểm cuối giàu tính năng nhưng hiệu suất kém hơn, bạn có thể sử dụng Mongoose

Lưu ý cuối cùng, vui lòng nếu bạn muốn nhận thêm hướng dẫn về MongoDB, JavaScript và Bảo mật ứng dụng

Chúng ta nên sử dụng cầy mangut hay MongoDB?

Mongoose không phải là thư viện ODM duy nhất, còn có các lược đồ hapijs/joi, MongoDB, v.v. Và mặc dù Mongoose đặc biệt tốt trong lĩnh vực suy luận các loại dữ liệu, chúng ta nên chọn sử dụng xác thực lược đồ MongoDB để xác thực lược đồ .

Sự khác biệt giữa cầy mangut so với MongoDB là gì?

Mongoose là thư viện Mô hình hóa dữ liệu đối tượng (ODM) cho MongoDB và Node. js . Nó quản lý các mối quan hệ giữa dữ liệu, cung cấp xác thực lược đồ và được sử dụng để dịch giữa các đối tượng trong mã và biểu diễn của các đối tượng đó trong MongoDB. MongoDB là một cơ sở dữ liệu tài liệu NoSQL không có lược đồ.

Nhược điểm của cầy mangut là gì?

Nhược điểm chính của cầy mangut là tính trừu tượng đi kèm với chi phí hiệu năng so với trình điều khiển MongoDB .

Tôi nên sử dụng cầy mangut hay MongoDB Reddit?

Sử dụng mongodb thuần túy . Mongoose không thực sự cung cấp cho bạn bất cứ thứ gì đáng giá và chỉ là một nguồn lỗi mới. Mongoose là một ORM cho mongoDB. Nó cho phép bạn tạo các mô hình phức tạp và trợ giúp với các truy vấn bộ đệm (mặc dù tùy thuộc vào cấu hình của bạn).