【问题标题】:MongoDB Promise and Result ProcessingMongoDB Promise 和结果处理
【发布时间】:2017-12-28 13:38:09
【问题描述】:

我目前正在学习 nodejs 中的 Promises,现在我在处理 mongoDB 查询和 Promise 方面有点卡住了。这是我在下面的示例代码。

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() 之后添加“then”解决了我之前的问题,当它到达 db 插入代码时,promise 尚未解决。但是,既然我有另一个数据库查询,我该如何正确(再次)处理异步调用?上面的例子对吗?

在 DB 中不重复运行此代码(意味着第一个查询返回 null)将导致返回拒绝代码“访问数据库时发生错误,请联系管理员”(最后一个拒绝)。但是,数据库更新得很好,这意味着它应该到达 then 而不是 catch。查询应该在中间部分达到了解析并返回,但似乎代码以某种方式触发了捕获。

【问题讨论】:

  • 我会通过一些关于 Promise 如何工作的文章来跟进你的探索。这是一个示例:davidwalsh.name/promises.

标签: node.js mongodb express promise


【解决方案1】:

问题似乎归结为 Promise 是如何工作的。看起来代码中有两个相关但不同的事情:

  1. 使用从 Mongo 返回的承诺。
  2. 控制另一个承诺(可能由该函数返回)。

我们似乎也遗漏了一个细节——这是在返回另一个承诺的函数中吗?现在让我们假设你是并且它看起来像这样:

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

Promise 实际上只能“设置”一次。它们可以是resolvedrejected。但是,随后的 then()catch() 调用会返回新的 Promise。这使您可以将它们链接在一起以控制应用程序的流程。同样,您可以从 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()
   });

【讨论】:

  • 谢谢道格!现在我对这个问题有了更好的理解并解决了困惑。下面我还添加了一些更改,希望可以为其他人解释和分解问题。
  • 这是一个详细的演练。非常感激。谢谢
【解决方案2】:

感谢 Doug swain 之前!

现在看来我对 mongodb 和 Promise 有了更好的理解。前面代码的问题是我试图使回调和承诺过于复杂。代码function(err,success) 实际上是一个回调,它应该已经处理了结果。添加承诺。那么就没有必要了。

但是,当我尝试对所有节点进行承诺时,我将代码更改为使用承诺而不是回调。这是更简洁的最终代码。

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(...)后面不能直接使用.then。 find(...) 查询将返回游标而不是承诺。因此,.toArray()后面需要使用.then

【讨论】:

    【解决方案3】:
        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 和 finally

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-09
      • 2012-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-14
      • 1970-01-01
      相关资源
      最近更新 更多