mongodb 原生驱动?
发布于 7 年前 作者 leavesdrift 3594 次浏览 来自 问答

有几个关于 mongodb 原生驱动的问题?

第一个,简单封装问题

// 连接数据库并选定集合然后返回
const { MongoClient } = require('mongodb');
const { db } = require('config-lite')(__dirname);
const { format } = require('url')
const _ = require('lodash')
const url = format(_.omit(db.mongodb, 'collection'));

/*
db.mongodb 类似
 {
          protocol: 'mongodb:',
          hostname: '127.0.0.1',
          slashes: true,
          auth: null,
          port: '27017',
          pathname: '/xxxx',
          collection: {
            post: 'posts',
            admin: 'admins',
          }
*/
module.exports = function(collection, fieldOrSpec, options) {
    return MongoClient.connect(url)
                      .then(db => {
                         return db.collection(collection)
                      })
                      .then(col => {
                         return !_.isUndefined(fieldOrSpec) && _.isPlainObject(fieldOrSpec)
                                ? col.createIndex(fieldOrSpec, options)
                                     .then((indexName) => {
                                        return col
                                     })
                                : col
                      })
};

//  增删查改操作,截取部分
const connect = require('./_connect_v2');
const isPlainObject = require('lodash/isPlainObject')


module.exports = {
  count(collection, query, options) {
     return isPlainObject(collection)
            ? connect(...Object.values(collection))
              .then(col => {
                 return col.count(query, options)
              })
            : connect(collection)
              .then(col => {
                 return col.count(query, options)
              })
  },
  distinct(collection, key, query, options) {
     return isPlainObject(collection)
            ? connect(...Object.values(collection))
              .then(col => {
                 return col.distinct(key, query, options)
              })
            : connect(collection)
              .then(col => {
                 return col.distinct(key, query, options)
              })
  },
  insertOne(collection, data, options) {
     return isPlainObject(collection)
            ? connect(...Object.values(collection))
              .then(col => {
                 return col.insertOne(data, options)
              })
            : connect(collection)
              .then(col => {
                 return col.insertOne(data, options)
              })
  }
  }

不封装可能会有很长的链式操作,但是这样封装又会造成 没办法 db.close,并且我也有几个疑惑:

第一个问题: MongoClient.connect 是每次都会创建一个拥有一定数量的连接池么?如果是这样那我只是单次数据库查询不是会很不高效,比如我只需要获得一个集合的文档总数

第二个问题: 查询资料的过程中有说 MongodbClient.connect 是维护了一个 100 个连接的连接池,也有人放官网图说是 改成了单例模式,我想问的就是到底是哪种(虽然第二种可能性很小)? 并且mongodb单例模式在 Nodejs 中的实现是否会有所不同,因为 Nodejs 表面单线程,底层还是多线程实现异步,总之我对这些知识很混乱,希望有人能讲一下。

4 回复

额,你的表述性有些混乱,但基本问题我已了解; 首先、close或不close取决于你的项目需求,比如你是http的短连接请求,且请求量不大,那么每次close或许会(创建连接的代价也不小)高效些,但如果是长连接类聊天等高并发、实时性要求高的场景,长连接将是好的选择; 其次、创建一个connect连接或,默认情况下维护一个具有5个连接的连接池,你可以在本地shell打开一个终端,通过mongostat查看连接数,自己动手比什么都实在; 最后、连接池问题,你看下官方文档,在创建connect时有一个pool参数,默认是5个,这个大小可以自定义;

提问题要最小化,不然谁有空看那么长

@haozxuan 确实表述有些混乱,下次提问我会注意了。主要不太知道使用 promise 的时候,怎么让 mogodb 保持长连接呢?我对 mongodb 也并不是很了解,所以导致我也不知道怎么监控操作和连接状况。但是直到现在确实这个问题都困扰我,不封装 mongodb 原生驱动感觉有些时候比较累赘,链式可能写的很长。封装把就变成每次都需要 connect close 了,并且在 promise 中还难以传递 db 在操作之后 close,目前我是转到了 mongoose ,但是还是很想知道这个问题怎么处理?用代码表示就是:

// connect.js
const MongoClient = require('mongodb')

module.exports = MongoClient.connect
// db.js
const connect = require('./connect')
const url = require('../config').db.mongodb.url

module.exports = {
  insertOne(collection, data) {
      connect(url)
	     .then((db) => {
		    return db.collection(collection)
			               .insertOne(data)
		 })
		 /**
		  * 1. 想要达到的目标是长连接,但是在异步的情况下我不知道该怎么做
          * 2. 退而求其次选择短连接,但是由于使用了 promise ,导致关闭变得困难
		  * 3. 于是我的问题变成了在不使用 async/await 的情况下仅用 promise 怎么处理这两种情况
		  */
 }
}

@leavesdrift 从你的第二次描述看,其实你并不关注关闭和创建带来的性能损耗,而是关注怎么优雅的用Promise进行易步流控制,目前我使用的是async,大致封装情况如下图,希望能够对你有所帮助: image.png

回到顶部