Meteor数据库连接

6
我是一个有用的助手,可以翻译文本。
我正在尝试连接Mongo数据库,该数据库位于我的Meteor应用程序所在的计算机上。这里有两个文件在我的应用程序中:
a.js:
if (Meteor.isServer) {

    var database = new MongoInternals.RemoteCollectionDriver("mongodb://127.0.0.1:3001/meteor");
    Boxes = new Mongo.Collection("boxes", { _driver: database });
    Meteor.publish('boxes', function() {
        return Boxes.find(); 
    }); 
}

b.js:

if (Meteor.isClient) {
    Meteor.subscribe('boxes');
    Template.homeCanvasTpl.helpers({
        boxes: function () {
            return Boxes.find({});
        }
    });
}

但是我一直收到一个“模板助手异常:引用错误:未定义Boxes”的错误-有什么想法吗?

你没有在客户端定义集合。你必须在服务器和客户端上都定义它。我认为在客户端定义时不需要传递任何第二个参数,因为你仍然会使用默认连接到服务器的方式。 - Jay
3个回答

19

如何使用Meteor连接到MongoDB?

方案A:使用内置的默认数据库

这比你之前做的要简单得多。当你运行meteor时,实际上会启动一个带有Meteor服务器的数据库,其中Meteor在端口3000上监听,数据库在端口3001上监听。Meteor应用程序已经连接到此端口为3001的数据库并使用名为meteor的DB。完全不需要退回到MongoInternals.RemoteCollectionDriver。只需删除那段代码并进行以下更改:

 Boxes = new Mongo.Collection("boxes"); // use default MongoDB connection

方案B:使用其他数据库作为默认

通过设置MONGO_URL环境变量,您可以在启动Meteor服务器时将连接字符串设置为MongoDB。您可以指定确切的连接位置和方式,而不是使用本地端口3001数据库或未经身份验证的连接。像这样启动Meteor服务器:

$ MONGO_URL=mongodb://user:password@localhost:27017/meteor meteor

如果不需要身份验证,您可以在命令中省略user:password@部分。

场景 C: 从同一个Meteor应用程序连接到第二个(第三个等)数据库

现在我们需要使用MongoInternals.RemoteCollectionDriver。如果您想要使用不是在启动Meteor服务器时定义的默认数据库,则应该使用您的方法。

var database = new MongoInternals.RemoteCollectionDriver('mongodb://user:password@localhost:27017/meteor');
var numberOfDocs = database.open('boxes').find().count();

额外奖励: 为什么不应该在Mongo.Collection中使用MongoInternals

正如文档所示,您不应将任何Mongo连接传递给new Mongo.Collection()命令,而只能传递到另一个Meteor实例的连接。这意味着,如果您使用DDP.connect连接到不同的服务器,则可以使用您的代码-但是您不应该混合使用MongoInternalsMongo.Collection,它们不能良好地协同工作。


最简单的声明远程集合的方法是什么?类似于 var Boxes = database.open('boxes') 这样的方式可行吗? - jimmiebtlr
这并不是那么简单,因为在集合中有很多“魔法”超越了简单的数据库集合(例如响应性、跟踪操作日志等)。如果您可以不使用这些特性,场景C可以让您快速轻松地访问远程DB coll,只是不具备响应性。 - Stephan
请注意:集合可能看起来是空的,您需要进行插入才能查看数据。 - Ruben

1

根据评论区saimeunt的反馈,他/她指出MongoInternals在Meteor应用的客户端部分不可用。因此,解决方案是在客户端逻辑中添加"Boxes = new Mongo.Collection("boxes");"这一行代码 - 这是最终的工作解决方案:

a.js:

if (Meteor.isServer) {

    var database = new MongoInternals.RemoteCollectionDriver("mongodb://127.0.0.1:3001/meteor");
    Boxes = new Mongo.Collection("boxes", { _driver: database });
    Meteor.publish('boxes', function() {
        return Boxes.find(); 
    }); 
}

b.js

if (Meteor.isClient) {
    Boxes = new Mongo.Collection("boxes");
    Meteor.subscribe('boxes');
    Template.homeCanvasTpl.helpers({
        boxes: function () {
            return Boxes.find({});
        }
    });
}

不用在意上面的评论。看起来你已经解决了它。 :-) - Jay

0
Meteor有两个不同的环境:运行在Node.JS上的服务器环境和运行在浏览器中的客户端环境。
在您的代码中,您仅在服务器环境中声明了Boxes Mongo集合,您需要将此声明移出Meteor.isServer条件(顺便说一句,不要使用这些,将您的代码分离到server/,client/和lib/目录中)。
此外,不确定您是否需要以这种方式连接到MongoDB,也许您应该查看MONGO_URL环境变量,它可能已经实现了您所需的功能?(提供到远程(或本地)Mongo服务器的mongo连接URL)。

我将声明从Meteor.isServer条件中移出(移到其上方),现在我遇到了这个错误:“MongoInternals未定义” - 有什么想法吗?附言:我正在尝试使用此方法,因为它被推荐在Stack Overflow的其他地方作为一种取代MONGO_URL的方法。 - JoeTidee
然后尝试使用两个声明,一个在服务器上使用 MongoInternals 工具,另一个在客户端上不使用。 - saimeunt
使用两个声明与文档中的一个声明在任何isClient/isServer块之外的规定相矛盾,因此生成的变量在整个应用程序中是全局可访问的。 - JoeTidee
1
请再次阅读我的回答:Meteor 中有两个环境,因此变量在整个应用程序中并不真正可用,单个声明总是会生成与两个不同环境对应的两个不同版本的变量。在您的特定情况下,您无法在两个环境上无缝地声明集合,因为 MongoInternals 在客户端不可用,因此您必须依靠两个单独的声明。 - saimeunt
我再次阅读了您的回答,没有看到您说MongoInternals对客户端不可用的任何内容。既然您提到了这一点,能否指引我和其他人查阅相关文档? - JoeTidee
没有MongoInternals的文档,因为我猜这应该是一个高级的MongoDB配置API,只在服务器上可用,在客户端只有minimongo,它是MongoDB API的内存子集。 - saimeunt

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