使用Node.js连接到MongoDB的最佳方法

9

我已经阅读了一些关于如何在Node中使用Mongo的指南,它们似乎都以不同方式连接到数据库。对我而言特别有效的是:

MongoClient.connect("mongodb://localhost:27017/exampleDb", function(err, db) {
  if(err) { return console.dir(err); }

  db.createCollection('users', function(err, collection) {});

  //Do all server/database operations in here

});

然而,我觉得这种方法效率低下/不合理。每次有app.get(),比如创建新用户或检索信息,我都需要重新连接到数据库。

另一种方式更适合我:

var mongoose = require("mongoose")
var db = mongoose.connect("localhost:27107/users");

db.createCollection('users', function(err, collection) {});

我看到很多网站都是这样做的,但是我个人无法让上述代码正常工作。服务器端一直出现错误 TypeError:db.createCollection不是一个函数。因此,我的问题是为什么上述代码无法正常工作,如果第一个代码是一个好的替代方案,还有没有其他方法可以做到这一点。

4个回答

17
你可以使用一个全局变量(例如db)来保存连接,比如:
var db = null // global variable to hold the connection

MongoClient.connect('mongodb://localhost:27017/', function(err, client) {
    if(err) { console.error(err) }
    db = client.db('test') // once connected, assign the connection to the global variable
})

app.get('/', function(req, res) {
    db.collection('test').find({}).toArray(function(err, docs) {
        if(err) { console.error(err) }
        res.send(JSON.stringify(docs))
    })
})

或者,如果您愿意,您也可以使用由MongoClient返回的Promise对象,而无需传递回调参数:

var conn = MongoClient.connect('mongodb://localhost:27017/') // returns a Promise

app.get('/', function(req, res) {
    conn.then(client=> client.db('test').collection('test').find({}).toArray(function(err, docs) {
        if(err) { console.error(err) }
        res.send(JSON.stringify(docs))
    }))
})

请注意,我在第二个示例中使用了ES6箭头函数定义
您是完全正确的,不应该每次调用MongoClient。使用全局变量或Promises允许MongoDB node.js驱动程序创建连接池,这至少实现了两个好处:
  • 池中重复使用连接,因此在应用程序的生命周期内没有多个昂贵的设置/拆卸过程。您只需连接一次,然后让驱动程序为您处理其余部分。
  • 您可以通过限制连接池的大小来控制应用程序进入数据库的连接数。
编辑2018-08-24:在node.js驱动程序版本3.0及更高版本中,MongoClient.connect()方法返回客户端对象而不是数据库对象。上面的示例已进行修改,以使其与最新的node.js驱动程序版本保持一致。

我遇到了通用处理程序 TypeError: db.collection 不是一个函数的错误。当我使用你的第一个示例时出现了这个问题。我该如何解决这个问题? - Syed Ayesha Bebe
请查看已更新的答案。 - kevinadi
你能否展示一下如何正确创建池以便重复使用,以及如果其中一个出现错误时如何进行更新? - Manohar Reddy Poreddy

1
我已经写了一份关于如何在Express中重用mongodb连接的教程。你可以在这里看到。基本上,它是一个简单的模块,你可以像这样与expressjs一起使用:
var connection = require('./dbconnection');  
// url and optional config.
app.use(connection(app, 'mongourl', {});

这是连接的代码:

module.exports = function(app, uri, opts) {  
    if (typeof uri !== 'string') {
        throw new TypeError('Error: Unexpected mongodb connection url');
    }

    opts = opts || {};
    var property = opts.property || 'db';

    var connection;
    return function expressMongoDb(req, res, next) {
        if (!connection) {
            connection = MongoClient.connect(uri, opts);
        }

        connection
            .then(function (db) {
                req[property] = db;
                app.set('mongodb', db);
                next();
            })
            .catch(function (err) {
                connection = undefined;
                next(err);
            });
    };
};

0
你可以这样使用它:
那是 server.js 文件:
import path from 'path'
import express from 'express'
import bodyParser from 'body-parser'
import morgan from 'morgan'
import db from './server/database'
import routes from './server/routes'

import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import webpackConfig from './config/webpack'
const app = express()
const port = process.env.PORT || process.env.NODE_PORT
const compiler = webpack(webpackConfig)

db(λ => {
  app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: webpackConfig.output.publicPath }))
  app.use(webpackHotMiddleware(compiler))
  app.use(morgan('dev'))
  app.use(bodyParser.json({ limit: '20mb' }))
  app.use(bodyParser.urlencoded({ limit: '20mb', extended: false }))
  app.use('/static', express.static('static'));
  //app.use('/api', jwt)
  app.use('/api', routes())

  app.set('json spaces', 2)

  app.get('*', function(request, response) {
    response.sendFile(path.resolve(__dirname, 'index.html'))
  })

  app.listen(port, (error) => {
    if (error) {
      console.error(error)
      throw error
    } else {
      console.info(`==>   Listening on port ${port}. Open up http://localhost:${port}/ in your browser.`)
    }
  })
})

server/database.js

import mongoose from 'mongoose'

export default callback => {
  const { MONGO_URL, MONGO_PORT, MONGO_DB } = process.env

  mongoose.connect(`mongodb://${MONGO_URL}:${MONGO_PORT}/${MONGO_DB}`, error => {
    if (error) {
      console.error('Please make sure your MongoDB configuration is correct and that service is running')
      throw error
    }
  })

  callback()
}

接下来您需要定义您的Mongoose模型,例如:

import mongoose, { Schema } from 'mongoose'

const ideaSchema = new Schema({
  title: {
    type: String,
    required: true
  },
  slug: {
    type: String,
    required: true,
    unique: true
  },
  description: {
    type: String,
    required: true
  }
})

export default mongoose.model('Idea', ideaSchema)

只需这样使用控制器:

import HttpStatus from 'http-status-codes'
import mongoose from 'mongoose'
import sanitize from 'sanitize-html'
import slug from 'slug'
import Idea from '../models/idea'

const findAllIdeas = (req, res) => {
  Idea.find()
    .select('user title slug createdAt updatedAt')
    .populate({
      path: 'user',
      select: 'firstName lastName'
    })
    .then(data => res.status(HttpStatus.OK).json(data))
    .catch(error => res.status(HttpStatus.BAD_REQUEST).json(error))
}

export default { findAllIdeas, findIdeaBySlug, createIdea, addComment }

你不需要在每个get请求中连接到mongoDB。

所以你的路由看起来很简单:

import { Router } from 'express'
import controller from '../controllers/idea'

const router = Router()

router.route('/')
  .get(controller.findAllIdeas)
  .post(controller.createIdea)

router.route('/:slug')
  .get(controller.findIdeaBySlug)

router.route('/comment')
  .post(controller.addComment)

export default router

非常有趣,感谢您的帮助。尽管我会努力理解,但个人还是有些犹豫使用我不太理解的代码。 - db2791
我认为这比 OP 要求的多了一些... - Lucas Watson

-2

我常用的代码如下:

mongoose.connect(YOUR_URL ,function(err) {
  if (err) {
    console.log(err);
  }else{
    console.log("Connected to DB"); 
  }
});

也可以尝试连接到 localhost:27107,这可能是您的问题。


是的,那样做没问题,但正如我所问的那样,它是否足够高效,可以用于每个"app.get()"呢?还是说这不是一个问题? - db2791
是的,只需将这段代码放入 server.js 中,在其他需要查询 MongoDB 的文件中,只需使用 var mongoose = require('mongoose');,然后使用 var Model= require('./models/MODEL');。如果在 server.js 中,它只会在启动时连接一次。 - Lucas Watson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接