Node.JS、Express 和 MongoDB :: 多个集合
Posted
技术标签:
【中文标题】Node.JS、Express 和 MongoDB :: 多个集合【英文标题】:Node.JS, Express & MongoDB :: Multiple Collections 【发布时间】:2013-08-20 10:05:28 【问题描述】:我正在使用 Node.JS、Express、MongoDB 和 EJS。我有一个关于一个数据库下的多个 MongoDB 集合的问题,并调用它们在前端使用。我有 3 个集合,经过大量研究后,还没有找到如何调用多个集合而不会出错。
我知道将所有内容存储在一个集合中不会有问题,但我觉得最好的方法是按类别将它们分开。这是我的数据库/集合调用:
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
所以我在名为“michael”的数据库下的 MongoDB 中有两个集合,我试图在一个 MongoClient.connect() 下调用它们。然后,我将结果以两个数组的形式(通过 EJS)发送到前端:“portfolio”和“about”。似乎当我这样做时,它会使“投资组合”未定义。希望这是有道理的。
【问题讨论】:
感谢您的回复。这是错误:“ReferenceError: /Volumes/Files/WebDev/RHC/michael/michael/views/index.html:62db.collection
调用,在同一个数据库查询中引用一个新集合时,页面将在某些刷新时呈现,并在其他页面上跳过所有 CSS。似乎试图调用另一个集合并将其推送到前端会混淆 EJS,并呈现之前的集合 var undefined。
您可能需要添加更多细节(尤其是您的问题何时/如何发生错误)
好的,我添加了更多细节。
你为什么要渲染“index.html”两次?
【参考方案1】:
我也有同样的问题,现在我知道这与你不能 res.render() 两次的事实有关。有人推荐一个解决方案:使用socket.io。 我想知道是否有另一种解决方案,就我而言,我想从 2 个不同的 mongoDB 集合中获取食谱和作者,但我不能只用 1 个 res.render() 来做到这一点,不敢相信 node.js + express + mongoose 不会完成一些简单的事情,比如说... LAMP。
【讨论】:
这很奇怪。那么在 Mongo 的一个 db 下拥有多个集合有什么意义呢? 其实我已经想通了,所以我之前的评论是没用的。我发现了 2 种不同的方法来执行 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 ); ); 谢谢! Autores 和 Recetas 是两个不同的系列,是吗?是否可以将此作为答案发布?对我来说,解决方案#1 很容易理解(而且不是那么难看!),而#2 不太理想,因为它修改了架构。龚来试试这个! 是的,它们是不同的集合。第二种解决方案创建了一个类似于 mysql 关系的“关系”。 好的,我尝试了您建议 aesede 的修改版本,并且成功了!特别是res.render('index', recetas: recetas, autores: autores );
做到了。【参考方案2】:
好的,使用 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 中呈现的任何内容。但是,任何后续刷新都会始终如一地显示内容。
【讨论】:
不要像这样嵌套你的集合调用,你可能想看看async。它是一个支持处理多个异步进程的模块,具有在所有个进程完成后调用函数的能力。 酷,我去看看!【参考方案3】: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 返回对象,而且当你使用数组而不是对象时,你可能会遇到一些类型错误
【讨论】:
【参考方案4】:这个问题实际上有一个非常简单、直观的答案。这绝对不是优雅的,我确实认为 Express、Mongoose 和 NodeJS 的更新应该包括一种预设的方式来执行此操作,而不必从逻辑上考虑整个过程。
你所要做的就是为你想要传递到页面的每个集合嵌套你的 find() 调用。下面的例子:
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 函数并更“优雅地”执行此任务。但与此同时,请使用我上面的示例,因为我相信这是实现此目的最直观的方式。
【讨论】:
【参考方案5】: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 );
)
)
)
【讨论】:
以上是关于Node.JS、Express 和 MongoDB :: 多个集合的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 mongodb、node.js、express 和 EJS 创建动态站点地图?
Node.js /Express 和 mongoose:通过自动拉取新数据建立“可观察”的 mongodb 连接?
使用 Express 和 Node JS 在 MongoDB 中上传文本文件
node.js + express.js:使用 mongodb/mongoose 处理会话