【问题标题】:Asynchronous issue within nodejs/mongodb codenodejs/mongodb 代码中的异步问题
【发布时间】:2016-09-03 03:20:05
【问题描述】:

我是 nodejs/express/mongodb/jade 的新手,一段时间以来我一直在尝试建立一个简单的站点,以帮助以更有效的方式返回过去的数据并能够快速重用它。我确定对我们来说最简单的方法是使用动态 URL,并且已经开始取得良好进展,然后遇到了障碍。

最终目标:我希望使用 URL 参数来确定返回哪些数据。在本地运行,语法看起来像 localhost/:collection/:id。例如,它看起来像:localhost/lastyear/aug2001。因此,结果页面将显示去年集合中 _ID 等于 aug2001 的数据。

为了实现这一点,我目前将 index.js 中的路由设置为:

var express = require('express');
var router = express.Router();

router.get('/:collection/:id', function(req, res) {
    var db = req.db;
    var collection = db.get(req.params.collection);
    var entry = collection.findOne({ id: req.params.id },{})
    res.render('dataentry',{ title: 'Information for: ' + req.params.collection + ' ' + req.params.id +'.', data: entry
    });   
});

module.exports = router;

集合中文档的结构如下所示:

{
     "_id": "aug2001"
     "header": "header text"
     "content": "content text"
     "item" : "items text"
}

为了测试查看某种形式的数据,我用于数据输入的翡翠文件如下所示(我知道制表符在翡翠中很重要,在帖子中它可能看起来不正确,但我确保制表符是正确的):

block content 
     p Finding info...
     p= data.header
     p= data.content
     p= data.item

当导航到 /lastyear/aug2001 时,我看到的只是页面加载“正在查找信息...”,我不确定为了显示 doc 数据而使用玉语法时我缺少什么。我感谢任何帮助/建议以更有效的方式来实现我的最终结果。

编辑: 真正的问题不是 JADE 显示,而是从数据库中提取数据时的异步数据库调用。

【问题讨论】:

  • 这里发生了很多事情 - 作为第一步,您应该尝试隔离您的问题。例如,问题是在 Jade 中还是在 db 查询中?要测试这一点,你可能会例如在res.render() 之前写console.log(entry); 以查看是否正确找到数据库对象。如果你没有看到你所期望的,你知道你的问题出在你的数据库调用上,而不是你的 Jade。
  • 感谢您的评论。这里肯定发生了很多事情,我很欣赏你的评论。我继续添加代码,虽然我对 console.log() 的标准输出不太熟悉,但输出看起来不正确。我继续将它添加到我在开始我自己的项目之前的工作教程中,当在控制台中运行它时,它会显示集合中文档的实际数据结构。因此,我的 db 调用有问题。谢谢您的帮助。将在我解决问题时更新/编辑问题。

标签: javascript node.js mongodb express pug


【解决方案1】:

据我所知,您在这里遇到了异步问题。

这样试试

router.get('/:collection/:id', function(req, res) {
   var db = req.db;
   var collection = db.get(req.params.collection);
   //this is async operation so you need to wait until it finish.
   //and only then send response to page.
   collection.findOne({ id: req.params.id },{}, function(err, entry){
      res.render('dataentry',{ title: 'Information for: ' + req.params.collection + ' ' + req.params.id +'.', data: entry
      });  
   }); 
});

希望这会有所帮助。

【讨论】:

  • 感谢您的解释和帮助。我不再在我的数据库调用中收到空结果。谢谢。
  • Np. 很高兴为您提供帮助
【解决方案2】:

代码未检查


正如@Mykola Borysyuk 提到的,这似乎是一个异步回调问题。在您的代码中,collection.findOne({ id: req.params.id },{}) 是一个异步函数,因此您不知道它何时会被执行。当您从函数回调外部渲染页面时,在渲染调用发生之前似乎没有修改条目。

正如上面的答案中提到的,一种方法是创建一个回调函数,并从回调内部呈现页面。正如@Mykola 所展示的那样。为了清楚起见,我在下面给出。

var collection = db.collection(req.params.collection);
   collection.findOne({ id: req.params.id },{}, function(error, data){
     if(error){
       console.log("Error: " + error);
     }
     else {
       res.render('dataentry',{ title: 'Information for: ' + req.params.collection + ' ' + req.params.id +'.', data: data});
     }
   });

这应该可以正常工作。话虽如此,还有另一种方法可以让渲染操作等到异步函数完成执行。这可以使用 Promise 来完成。

可以这样做:

var collection = db.collection(req.params.collection);
res.promise(collection.findOne({ id: req.params.id },{},function(error,data)).then(function(){
    res.render('dataentry',{ title: 'Information for: ' + req.params.collection + ' ' + req.params.id +'.', data: data});
});

我还没有检查我的代码,但希望这会有所帮助!

【讨论】:

  • 感谢您对承诺的解释。也可以进一步研究。
  • 总是乐于提供帮助!
  • 看起来我在通过 _id 查找时遇到了“传入的参数必须是 12 个字节的单个字符串或 24 个十六进制字符的字符串”错误。如果我将它更改为 collection.findOne({ item: req.params.id } 并且 url 参数匹配一个项目,那么它不会抛出错误。查看 _id 上的 MongoDB 文档我知道 ObjectID 有一些东西,但它我无法理解这个问题。你是否熟悉这个错误,你可以进一步解释它吗?
  • 嘿。据我了解,ObjectID 是由包含对象时间戳的数据库生成的。这样,每个对象都有一个唯一的 ObjectID。默认情况下,_id 键包含 ObjectID 值。您可以生成自己的 _id,但 ObjectID 是由 db 生成的。您的 _id 变量可以包含任意数量的字符,但 ObjectID 变量的大小是固定的。尝试打开您的 mongo cli 界面并输入 `db..find().pretty() 以查看您的数据库的结构。似乎您正试图通过将 ObjectID 与生成的 _id 等同起来从 db 中检索。
猜你喜欢
  • 1970-01-01
  • 2020-07-26
  • 2013-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多