Node.JS、Express 和 MongoDB:多个集合

8
我正在使用Node.JS、Express、MongoDB和EJS。我有一个关于一个数据库下多个MongoDB集合的问题,并在前端调用它们时出现了问题。我有3个集合,经过很多研究,我没有找到如何调用多个集合而不出错的方法。
我知道把所有东西都存储在一个集合下不会有问题,但我觉得最好的方法是按类别分开它们。这是我的db/collection调用:
app.use(express.bodyParser());
var MongoClient = require('mongodb').MongoClient;

app.get('/', function(req, res){
  MongoClient.connect("mongodb://localhost:27017/michael", function(err, db) {
    if(!err) {
      console.log("We are connected");
    }
    db.collection("portfolio", function(err, collection) {
      collection.find().sort({order_num: 1}).toArray(function(err, result) {
        var portfolio = [];
        if (err) {
          throw err;
        } else {
          for (i=0; i<result.length; i++) {
            portfolio[i] = result[i];
          }
          res.render('index.html', {portfolio: portfolio});
        }
      });
    });
  });
});

我该如何对其他集合进行多次调用,例如“关于”集合等?我尝试添加另一个...
db.collection("about", function(err, collection) {

"...在...范围内..."
MongoClient.connect("mongodb://localhost:27017/michael", function(err, db) {

...但是它在终端控制台日志中给我错误提示。
提前感谢您的帮助。
编辑:
以下是我尝试做的事情,但是它给了我一个错误:
app.get('/', function(req, res){
  MongoClient.connect("mongodb://localhost:27017/michael", function(err, db) {
    if(!err) {
      console.log("We are connected");
    }
    db.collection("portfolio", function(err, collection) {
      collection.find().sort({order_num: 1}).toArray(function(err, result) {
        var portfolio = [];
        if (err) {
          throw err;
        } else {
          for (i=0; i<result.length; i++) {
            portfolio[i] = result[i];
          }
          res.render('index.html', {portfolio: portfolio});
        }
      });
    });
     // Here's the additional collection call:
     db.collection("about", function(err, collection) {
      collection.find().sort({order_num: 1}).toArray(function(err, result) {
        var about = [];
        if (err) {
          throw err;
        } else {
          for (i=0; i<result.length; i++) {
            about[i] = result[i];
          }
          res.render('index.html', {about: about});
        }
      });
    });
  });
});

这是控制台中的错误:
ReferenceError: /Volumes/Files/WebDev/RHC/michael/michael/views/index.html:62
60|               <div class="row-fluid">
61|                 <ul id="work" class="thumbnails">
>> 62|                     <% for(i=0; i<portfolio.length; i++) { %>
63|                         <% if (portfolio[i].proj_type == "work") { %>
64|                             <% var newLine = ""; %>
65|                             <% var fancyBox = ""; %>

portfolio is not defined

所以我在 MongoDB 中有两个集合,都在名为“michael”的数据库下,我正在尝试在一个 MongoClient.connect() 下调用它们。然后我将结果分别存储在两个数组中,通过 EJS 将它们发送到前端:"portfolio" 和 "about"。当我这样做时,似乎渲染 "portfolio" 时出现了未定义的错误。希望这样说得清楚了。

感谢回复。以下是错误信息:"ReferenceError: /Volumes/Files/WebDev/RHC/michael/michael/views/index.html:62 <snippet from code showing offending line> var_name is not defined at <list of offending items>" 对不起,完整的错误信息太长无法在评论中显示。 - michaelzick
有趣的是,当我添加一个新的 db.collection 调用时,在同一数据库查询中引用一个新的集合,页面会在某些刷新时呈现,并在其他情况下跳过所有 CSS。似乎尝试调用另一个集合并将其推送到前端会使 EJS 混淆,并呈现先前的集合变量未定义。 - michaelzick
你可能想在你的问题中添加更多细节(特别是错误发生的时间/方式)。 - WiredPrairie
好的,我添加了更多细节。 - michaelzick
在调用渲染之前,您需要确保两个请求都已完成。 - WiredPrairie
显示剩余2条评论
5个回答

7

好的,使用aesede的解决方案并加上我的修改,我成功地呈现了两个收藏夹。可能还需要一些微调,但这就是我得到的结果:

// GLOBAL ARRAYS FOR STORING COLLECTION DATA
var collectionOne = [];
var collectionTwo = [];
app.get('/', function(req, res){
  MongoClient.connect("mongodb://localhost:27017/michael", function(err, db) {
    if(!err) {
      console.log("We are connected");
    }
    db.collection("collectionOne", function(err, collection) {
      collection.find().sort({order_num: 1}).toArray(function(err, result) {
        if (err) {
          throw err;
        } else {
          for (i=0; i<result.length; i++) {
            collectionOne[i] = result[i];
          }
        }
      });
      db.collection("collectionTwo", function(err, collection) {
        collection.find().sort({order_num: 1}).toArray(function(err, result) {
          if (err) {
            throw err;
          } else {
            for (i=0; i<result.length; i++) {
              collectionTwo[i] = result[i];
            }
          }
        });
      });
      // Thank you aesede!
      res.render('index.html', {
        collectionOne: collectionOne,
        collectionTwo: collectionTwo
      });
    });
  });
});

就本身而言,我发现的唯一一个错误是:当Node重新启动并且我在浏览器中点击“刷新”时,我没有看到任何内容呈现在HTML中。但是,任何后续的刷新都会一致地显示内容。


1
与其像这样嵌套您的集合调用,您可能想要查看 async。它是一个支持处理多个异步进程的模块,具有在所有进程完成时调用函数的能力。 - mattsch
好的,我会去看看! - michaelzick

2

其实,这个问题有一个非常简单、直观的答案。虽然我认为更新Express、Mongoose和NodeJS应该包含一种预设方式来完成这个过程,而不是需要逻辑思考。

你所要做的就是将每个集合的find()调用嵌套到彼此中,以便将它们传递到页面。下面是一个示例:

```javascript Collection1.find({}, function(err, result1) { Collection2.find({}, function(err, result2) { res.render('page', {result1: result1, result2: result2}); }); }); ```

其中,Collection1和Collection2分别是要传递到页面的两个集合。

app.get("/", function(req, res) {
     Collection.find({}, function(err, collection) {
          if(err) {
               console.log(err);
          } else {
               Collection2.find({}, function(err, collection2) {
                    if(err) {
                         console.log(err)
                    } else {
                         res.render("page", {collection: collection, collection2: collection2});
                    }  
               }); 
          }
     });
});

你可以一直这样做,但显然这个概念不可扩展。如果你有30个不同的集合要遍历,这将是一个非常不方便的方法。
根据我所做的研究,这并不像应该那么简单,因为Collection.find()方法实际上是一个Promise函数。如果它不是一个Promise函数,我们可以简单地为每个集合运行find()方法,将结果传递到全局对象中,并将整个对象通过渲染传递。但你不能这样做,因为全局变量会在promise函数完成之前初始化并通过渲染传递。你最终会传递一个空对象通过渲染。我知道这是因为我尝试过。
我没有Promise函数的经验。我将进行一些研究,看看是否有一种方式来构造你的代码以利用Promise函数并更加"优雅地"执行此任务。但与此同时,请使用我上面的示例,因为我认为这是最直观的方法来完成此任务。

0
app.get("/customer",function(req,res) {
    var orders={}; //Create Empty order Object
    var products={}; //Create Empty product Object
    Product.find({},function (err,allproducts) {
        if (err) {
            console.log(err);
        } else {
            //Find Collection And Assign It To Object
            products=allproducts;             
        }
    });
    Order.find({}).sort({"date":'desc'}).exec(function(err, allOrders) {
        if (err) {
            console.log(err);
        } else {
            //find order collection and sort it in desending order and assign it to order object  
            orders=allOrders;
            res.render("./customer/dashboard",{products:products , orders:orders});
        }
    });

});

我曾经遇到过同样的问题,我通过上述机制解决了它。我建议使用空对象而不是数组,因为MongoDb返回对象,如果你使用数组而不是对象,可能会遇到一些类型错误。


0

我也遇到了同样的问题,现在我知道这与不能两次使用res.render()有关。有些人建议使用socket.io来解决这个问题。 我想知道是否还有其他解决方案,在我的情况下,我想从2个不同的mongoDB集合中获取食谱和作者,但我无法仅使用1个res.render()完成,无法相信node.js + express + mongoose无法像LAMP一样轻松地完成这样简单的任务。


很奇怪。那么,在Mongo中一个数据库下有多个集合的意义是什么? - michaelzick
其实我已经想到了,所以我的上一条评论是无用的。 我找到了两种不同的方法来完成OP的要求:1(丑陋的) Recetas.find({}).exec(function (err, recetas) { if(err) { ... } Autores.find({}, function (err, autores) { if(err) { ... } res.render('index', { recetas: recetas, autores: autores }); }); });2(漂亮的) 添加到模式中:autor_id: { type: Schema.Types.ObjectId, ref: 'Autores' }然后Recetas.find({}).populate('autor_id').exec(function (err, recetas) {
if(err) { console.log(err) } res.render('index', { recetas : recetas }); });
- aesede
谢谢!Autores和Recetas是两个不同的集合,对吗?可以把这个发表为答案吗?对我来说,解决方案#1很容易理解(并且并不那么丑陋!),而#2则不太理想,因为它修改了架构。将要尝试这个! - michaelzick
是的,它们是不同的集合。第二种解决方案创建了一个类似于MySQL关系的“关系”。 - aesede
好的,我尝试了一下你修改过的建议aesede,它起作用了!特别是res.render('index', { recetas: recetas, autores: autores });这一行代码。 - michaelzick
太棒了!当你更熟悉mongoose时,你应该尝试使用“populate”。但这取决于你需要做什么,问候! - aesede

0
function mongoConnection() {
    return new Promise((res, rej) => {
        try {
            MongoClient.connect(conn_url, {},
                function (err, client) {
                    if (err) { res(false); }
                    else {
                        promise_db_connection = new Promise((resolve, reject) => {
                            var db = client.db(Database);
                            resolve(
                                {
                                    'collection_1': db.collection("collection_1"),
                                    'collection_2': db.collection("collection_2"),
                                    'collection_3': db.collection("collection_3")
                                }
                            );
                            res(true);
                        });
                    }
                }
            );
        } catch (error) {
            res(false);
        }
    })
}

mongoConnection().then((result) => {
    console.log(result ? 'Connection Successful' : 'Connection Failed');
})

app.get('/customer', (req, res) => {
    var product = [], order = []
    promise_db_connection.then((result) => {
        result.collection_1.find({}).toArray((err, data) => {
            if (!err) product = data;
            result.collection_2.find({}).toArray((err, data) => {
                if (!err) order = data;
            })
            res.render("page", { product: product, order: order });
        })

    })
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接