Nodejs 談談mongoose的promise化

Nodejs 談談mongoose的promise化

請問mongoose的API如何promise化 是否需要的話一個個自行用Q來封裝呢? 這樣一來 如果需要比較多的API 難免代碼重複和機械。

16 回复

Nodejs 談談mongoose的promise化

在使用Mongoose时,我们经常会遇到一些异步操作,比如查询、插入、更新和删除等。Mongoose默认使用回调函数来处理这些异步操作,但随着项目复杂度的增加,回调地狱(Callback Hell)会变得难以维护。因此,将Mongoose API Promise化可以极大地提高代码的可读性和可维护性。

为什么需要Promise化?

  1. 可读性:Promise使得异步代码看起来更像同步代码。
  2. 错误处理:Promise提供了一种统一的方式来处理错误,而不需要在每个回调中都处理错误。
  3. 链式调用:Promise支持链式调用,使得代码更加简洁。

如何Promise化?

Mongoose本身已经内置了对Promise的支持。从Mongoose v4.5.0版本开始,Mongoose已经默认使用内置的Promise库。你可以通过设置mongoose.Promise来自定义Promise库,例如使用bluebirdq

示例代码
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// 自定义Promise库
mongoose.Promise = global.Promise; // 使用Node.js内置的Promise

// 创建一个简单的Schema
const userSchema = new Schema({
    name: String,
    age: Number
});

// 创建模型
const User = mongoose.model('User', userSchema);

// 连接数据库
mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true, useUnifiedTopology: true });

// 使用Promise化的API
async function createUser() {
    try {
        const newUser = new User({ name: 'John Doe', age: 30 });
        await newUser.save();
        console.log('User saved successfully');
    } catch (error) {
        console.error('Error saving user:', error);
    }
}

async function findUser() {
    try {
        const user = await User.findOne({ name: 'John Doe' }).exec();
        if (user) {
            console.log('User found:', user);
        } else {
            console.log('User not found');
        }
    } catch (error) {
        console.error('Error finding user:', error);
    }
}

createUser();
findUser();

在这个例子中,我们创建了一个简单的用户模型,并使用async/await语法来处理异步操作。这种方式不仅提高了代码的可读性,还简化了错误处理。

结论

通过使用Mongoose内置的Promise支持,我们可以轻松地将Mongoose API Promise化,从而避免重复编写Promise封装代码。这样不仅可以提高代码的可读性和可维护性,还可以减少错误处理的复杂性。


mongoose本身就支持promise:

    var promise = Model.find().exec();
    promise.then(
      function(result) {
        // on resolve
      },
      function(err) {
        // on reject
      }
    );

我在koa里面使用的是原生的mongoose.

看mongoose的文档可以知道, Query#exec会返回promise. 只要返回类型是query的话,就可以执行exec方法, 这样就会返回一个promise. 这样就可以使用yield了 var user = yield User.findById(“xxxxxxxxxxxxxxxx”).exec()

如果是document, documet#save等方法, 就使用bluebird的promisify方法. yield Promise.promisify(user.save, user)()

所以基本上是不需要使用mongoose-q这种库的

怎么不可以, 我已经在用了. http://kmanjs.com 这里面我添加了 pre, 但是同样也使用了promisify, 没有任何问题 https://github.com/jeremial/kman/blob/master/server/models/user.js#L15 https://github.com/jeremial/kman/blob/master/server/paths/sign.js#L123

不知道这样行不行:

Model.find().exec().then(function(results) {
        // on resolve
      }).then(function(){
	  // on resolve
	  }).then(undefined,function(err) {
        // deal err
      });

Mongoose 的Promise 与ES6 Promise不一样 可以:

mongoose.Promise = Promise

mongoose默认的promise是mpromise。在mongoose 5.0中将被抛弃。如果native promise未实现,mongoose 5.0将采用bluebird。 针对4.1以上版本,我们可以手动修改mongoose中的promise: mongoose.Promise = require(‘bluebird’); 这样就可以使用catch等方法了。 参考文档:http://eddywashere.com/blog/switching-out-callbacks-with-promises-in-mongoose/

exports.findGroupDataByGroupKey = function *(groupKey) {
    const cb = yield new Promise((resolve) => {
        Admin.find(
            {'groups.groupKey': groupKey},
            {'groups': {$elemMatch: {groupKey: groupKey}}},
            function (err, group) {
                if (err) {
                    resolve({
                        err,
                        msg: true
                    });
                } else {
                    resolve({
                        err,
                        data: group[0].groups[0],
                        msg: false
                    });
                }
            });
    });
    if (cb.msg) {
        console.log(cb.err);
        return false;
    } else {
        return cb.data;
    }
};

这样是不是狠繁琐

原来返回的是promises对象

user.save方法该怎么promise化啊?直接用promisify好像不行啊

var journals = yield journalModel.find().exec(); this.body = yield render(‘list’, {journals:journals});

利用.exec() promise化,再利用yield得到结果即可。

好贴 mark

Mongoose 的 API 默认已经支持 Promises,这意味着你可以直接使用 .then().catch() 方法来处理异步操作。因此,你不需要手动使用如 Q 这样的库来封装 Mongoose 的 API。

示例代码

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/mydatabase', { useNewUrlParser: true, useUnifiedTopology: true });

// 定义一个简单的 Schema
const userSchema = new mongoose.Schema({
    name: String,
    age: Number
});

// 创建一个模型
const User = mongoose.model('User', userSchema);

// 使用 Promise 化的 API
User.find({}).then(users => {
    console.log(users);
}).catch(err => {
    console.error(err);
});

解释

  • 连接数据库:使用 mongoose.connect() 连接到 MongoDB 数据库。
  • 定义 Schema:创建一个简单的用户数据结构(Schema)。
  • 创建 Model:基于定义的 Schema 创建一个 Mongoose 模型 User
  • 查询数据:使用 User.find({}) 查询所有用户数据。由于 Mongoose 已经将这些方法 Promisify 了,所以可以直接调用 .then().catch() 来处理结果或错误。

通过这种方式,你可以避免手动封装 Mongoose 的 API,减少重复代码,并使代码更简洁和易读。

回到顶部