请大神指点,新手勿拍砖 Nodejs相关问题求解

请大神指点,新手勿拍砖 Nodejs相关问题求解

Post.getOneArticle = function(post_id, callback) { mongodb.open(function (err, db) { if (err) { return callback(err); } //查询post集合 db.collection(‘posts’, function (err, collection) { if (err) { mongodb.close(); return callback(err); } collection.findOne({"_id": new ObjectID(post_id) }, function (err, doc) { mongodb.close(); if (err) { return callback(err); } if(doc){ doc.post = markdown.toHTML(doc.post); //解析 markdown 为 html } callback(null, doc);//返回文章, 提示这行出错 }); }); //查询comment集合 db.collection(‘comments’, function (err, collection) { if (err) { mongodb.close(); return callback(err); } collection.find({ “post_id”: post_id }).sort({ time: -1 }).toArray(function (err, docs) { mongodb.close(); if (err) { return callback(err); } if(docs){ docs.forEach(function (doc) { //解析 markdown 为 html doc.content = markdown.toHTML(doc.content); }); } callback(null, doc);//返回评论 }); });

});

};

求大神指点,这代码应该怎么写才合理


2 回复

你当前的代码存在一些问题,主要是对数据库操作的逻辑处理不当。具体来说,你试图同时查询两个集合(postscomments),但没有正确地处理异步操作,导致可能出现并发问题或数据不一致的情况。

以下是修改后的代码:

const mongodb = require('mongodb'); // 假设你已经安装了mongodb模块
const ObjectID = mongodb.ObjectID;
const markdown = require('markdown-it')(); // 假设你使用的是markdown-it库

Post.getOneArticle = function(post_id, callback) {
    mongodb.open(function (err, db) {
        if (err) {
            return callback(err);
        }

        const postsCollection = db.collection('posts');
        const commentsCollection = db.collection('comments');

        Promise.all([
            postsCollection.findOne({ "_id": new ObjectID(post_id) }),
            commentsCollection.find({ "post_id": post_id }).sort({ time: -1 }).toArray()
        ]).then(([postDoc, commentDocs]) => {
            if (postDoc) {
                postDoc.post = markdown.render(postDoc.post); // 解析 markdown 为 html
            }
            
            if (commentDocs) {
                commentDocs.forEach(comment => {
                    comment.content = markdown.render(comment.content);
                });
            }
            
            callback(null, { post: postDoc, comments: commentDocs });

            db.close();
        }).catch((err) => {
            callback(err);
            db.close();
        });
    });
};

修改说明:

  1. Promise.all: 使用Promise.all来并行执行两个查询,确保两个查询都完成后才调用回调函数。
  2. Markdown 解析: 使用markdown.render方法来解析Markdown文本。
  3. 错误处理: 在所有操作完成之后关闭数据库连接,并在任何阶段发生错误时立即关闭数据库连接并调用回调函数传递错误信息。

这样可以保证在获取到文章和评论后,对它们进行Markdown的转换,并且在所有操作完成后正确地关闭数据库连接。


从你提供的代码来看,有两个主要问题:

  1. 数据库连接重复关闭:你在每个 db.collection 回调中都调用了 mongodb.close(),这会导致在第一个查询完成时就关闭了数据库连接。当第二个查询尝试使用已关闭的连接时,会导致错误。

  2. 回调参数不一致:在处理完第一个查询后,你调用 callback(null, doc),但在处理完第二个查询后,你又调用 callback(null, doc)。这里应该是传递两个参数给回调函数:一个是文章文档,另一个是评论列表。因此,应该修改为 callback(null, doc, docs)

以下是修改后的代码示例:

const mongodb = require('mongodb');
const ObjectID = mongodb.ObjectID;
const markdown = require('markdown').markdown;

Post.getOneArticle = function(post_id, callback) {
    mongodb.open(function (err, db) {
        if (err) {
            return callback(err);
        }
        
        db.collection('posts', function (err, postsCollection) {
            if (err) {
                db.close(); // 关闭数据库连接
                return callback(err);
            }
            
            postsCollection.findOne({ "_id": new ObjectID(post_id) }, function (err, doc) {
                if (err) {
                    db.close();
                    return callback(err);
                }
                
                if (doc) {
                    doc.post = markdown.toHTML(doc.post); // 解析 markdown 为 html
                }
                
                db.collection('comments', function (err, commentsCollection) {
                    if (err) {
                        db.close();
                        return callback(err);
                    }
                    
                    commentsCollection.find({ "post_id": post_id }).sort({ time: -1 }).toArray(function (err, docs) {
                        if (err) {
                            db.close();
                            return callback(err);
                        }
                        
                        if (docs) {
                            docs.forEach(function (doc) {
                                doc.content = markdown.toHTML(doc.content); // 解析 markdown 为 html
                            });
                        }
                        
                        db.close(); // 关闭数据库连接
                        callback(null, doc, docs); // 返回文章和评论列表
                    });
                });
            });
        });
    });
};

解释

  • 数据库连接只关闭一次:所有操作完成后,在最后一个回调函数中关闭数据库连接。
  • 正确传递参数:将文章和评论列表作为两个参数传递给回调函数。
  • 异步操作:确保所有数据库操作都在一个连接中完成,并在最后关闭连接。

这样可以确保代码逻辑清晰且不会因为多次关闭数据库连接而引发错误。

回到顶部