我目前正在学习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。查询应该在中间部分达到解决方案并返回,但似乎代码以某种方式触发了捕获。
答案 0 :(得分:4)
问题似乎归结为承诺如何运作。看起来代码中有两个相关但不同的东西:
我们似乎也错过了一个细节 - 这是否在一个返回另一个承诺的函数中?现在让我们假设你是,它看起来像这样:
function addNewUser(req) {
return new Promise(function(resolve, reject) {
// Insert the code from the question here.
});
}
承诺真的只能"设置"一旦。它们可以是resolved
或rejected
。但是,后续的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,最后根据您的需求