MongoDB承诺和结果处理

时间:2017-07-22 14:29:52

标签: node.js mongodb express promise

我目前正在学习nodejs中的Promises,现在我在处理mongoDB查询和承诺方面有点困难。以下是我在下面的示例代码。

db.collection(module.exports.collectionName).find( {"$or" :[{"email":req.body.email},{"username":req.body.username}]},function(err,success){
                if (err) {throw new Error("Error in accessing DB - check new user"); }
                return success;
            }).toArray().then(function(value){

                console.log(value.length);
                if (value.length == 0) {
                    db.collection(module.exports.collectionName).insertOne(insert,function(err,success){
                        if (err) {throw new Error("Error in accessing DB - insert new");}
                        return success;
                    }).then(function(value){
                        return resolve("Success")
                    }).catch(function(value){
                        return reject("Error happened during accessing DB, please contact the Admin inside");
                    });
                }
                return reject("Email / Username is not unique");
            }).catch(function(value){
                return reject("Error happened during accessing DB, please contact the Admin");
            });

很抱歉代码中有很多乱七八糟的东西。我想在这里询问有关查询处理的几件事。首先,我们如何正确处理mongodb查询中的错误,该错误据称由此

处理
,function(err,success){
            if (err) {throw new Error("Error in accessing DB - check new user"); }
            return success;
        }).

一段代码?

添加"然后"在toArray()解决了我之前的promise问题,当它到达db insert代码时尚未解决。但是,现在我内部有另一个数据库查询,如何正确(再次)处理异步调用?以上示例是否正确?

在DB中没有重复的情况下运行此代码(意味着第一个查询返回null)将导致返回拒绝代码"访问DB时发生错误,请联系管理员" (最后的拒绝)。但是,DB更新正常,这意味着它应该到达而不是catch。查询应该在中间部分达到解决方案并返回,但似乎代码以某种方式触发了捕获。

3 个答案:

答案 0 :(得分:4)

问题似乎归结为承诺如何运作。看起来代码中有两个相关但不同的东西:

  1. 使用Mongo返回的承诺。
  2. 控制另一个承诺(可能由此函数返回)。
  3. 我们似乎也错过了一个细节 - 这是否在一个返回另一个承诺的函数中?现在让我们假设你是,它看起来像这样:

    function addNewUser(req) {
      return new Promise(function(resolve, reject) {
        // Insert the code from the question here.
      });
    }
    

    承诺真的只能"设置"一旦。它们可以是resolvedrejected。但是,后续的then()catch()调用会返回新的Promises。这使您可以将它们链接在一起以控制应用程序的流程。同样,您可以从promise处理函数中返回一个新的Promise,以使它们按顺序工作。

    所以你的MongoDB查询看起来像这样:

    // First, run the initial query and get a Promise for that
    db.collection(module.exports.collectionName).find(...)
       .then(function(existingUsers) {
         // Now that we found what we need, let's insert a new value
         return db.collection(module.exports.collectionName).insertOne(...)
       })
       .then(function(addedUser) {
         // Now we know that we found existing users and insert a new one
         resolve(addedUser); // This resolves the Promise returned from addNewUser()
       });
    

    这可以控制MongoDB操作的顺序。如果您需要针对不同的情况进行特殊的错误处理(例如MongoDB错误与用户已存在的错误),您可以在需要时添加条件检查和调用catch()。例如:

    // First, run the initial query and get a Promise for that
    db.collection(module.exports.collectionName).find(...)
       .then(function(existingUsers) {
         if (existingUsers.length < 1) {
           // Now that we found what we need, let's insert a new value
           return db.collection(module.exports.collectionName).insertOne(...)
         }
    
         // Throw an error indicating we're in a bad place
         throw new Error('A user with this name already exists!');
       })
       .then(function(addedUser) {
         // Now we know that we found existing users and insert a new one
         resolve(addedUser); // This resolves the Promise returned from addNewUser()
       })
       .catch(function(err) {
         // This will run when an error occurs. It could be a MongoDB error, or perhaps the user-related error thrown earlier.
         reject(err); // This rejects the Promise returned from addNewUser()
       });
    

答案 1 :(得分:0)

感谢Doug swain!

现在我似乎对mongodb和承诺了解得更好。以前的代码的问题是我试图过度复杂的回调和承诺。代码function(err,success)实际上是一个回调,应该处理结果。添加承诺。然后没有必要。

但是,当我试图宣传所有节点时,我将代码更改为使用promise而不是回调。这是最后的代码,它更整洁。

db.collection(module.exports.collectionName).find(...).toArray().then(function(value2){
if (value2.length > 0){
    return reject("Email / Username is not unique");
}

db.collection(module.exports.collectionName).insertOne(insert).then(function(correct){
    return resolve(correct);
}).catch(function(error){
    throw new Error(error);
});

}).catch(function(err){
console.log(err);
return reject(err);
});

代码就像我想要的那样工作。 之前的代码也存在问题,因为在find(...)之后无法直接使用。 find(...)查询将返回游标而不是promise。因此,.toArray()之后需要使用.then

答案 2 :(得分:0)

    Mongoose returns a Promise. So if you can use Mongoose and await, it can solve your problems. 1 and 2 are areas which are somewhat tricky.


    let asyncFunction = async()=>{
    let success;
       let data = await db.collection(module.exports.collectionName).find( {"$or" :[{"email":req.body.email},{"username":req.body.username}]};
    })

//1
    new Promise((resolve, reject)=>{
     if(data.err){error code here}
     else{ resolve (data.toArray());
    }).then((val)=>{
      //val here is data.toArray() value 
      //2 here a callback can be used as insertOne will take time
      if(value.length == 0){
        db.insertOne((insert,(err, success)=>{
                            if (err) {throw new Error("Error in accessing DB - insert new");}
                            success = success;
    }

    })).then(()=>{//use success here..send response or return result})

使用catch,最后根据您的需求