在 Meteor 中如何有条件地向客户端发送数据?
Posted
技术标签:
【中文标题】在 Meteor 中如何有条件地向客户端发送数据?【英文标题】:How do you conditionally send data to the client in Meteor? 【发布时间】:2012-12-14 00:13:41 【问题描述】:我试图弄清楚如何有条件地将数据发送到meteor 中的客户端。我有两种用户类型,根据用户类型,他们在客户端上的界面(因此他们需要的数据不同)。
假设用户的类型为counselor
或student
。每个用户文档都有类似role: 'counselor'
或role: 'student'
的内容。
学生有sessionsRemaining
和counselor
等学生特定信息,辅导员有pricePerSession
等信息。
我如何确保客户端的Meteor.user()
拥有我需要的信息,而且没有多余的信息?如果我以学生身份登录,Meteor.user()
应该包括 sessionsRemaining
和 counselor
,但如果我以辅导员身份登录,则不会。我想我可能正在搜索的是流星术语中的有条件的出版物和订阅。
【问题讨论】:
我现在得到了一些答案,但我不确定我知道如何选择最好的,因为它们似乎都在表面上起作用。我想我想要最简单、最“流星”的版本,它适用于更复杂的情况(即角色不互斥时等) 在这种情况下,您可能应该选择@debergalis 的答案,因为他是 Meteor 的创造者之一。没有比这更流星了:) 【参考方案1】:使用 fields 选项仅从 Mongo 查询中返回您想要的字段。
Meteor.publish("extraUserData", function ()
var user = Meteor.users.findOne(this.userId);
var fields;
if (user && user.role === 'counselor')
fields = pricePerSession: 1;
else if (user && user.role === 'student')
fields = counselor: 1, sessionsRemaining: 1;
// even though we want one object, use `find` to return a *cursor*
return Meteor.users.find(_id: this.userId, fields: fields);
);
然后在客户端调用
Meteor.subscribe('extraUserData');
订阅可以在 Meteor 中重叠。因此,这种方法的巧妙之处在于,向客户端发送额外字段的发布功能与 Meteor 发送基本字段(如用户的电子邮件地址和个人资料)的幕后发布功能一起工作。在客户端,Meteor.users
集合中的文档将是两组字段的并集。
【讨论】:
一个微妙的提示:如果用户的角色可以动态改变,这个发布者不会注意到这一点并改变它正在发布的字段。如果你需要做类似的事情,你目前必须在observe
之上手动实现它;希望将来 Meteor 能够以某种方式进行完全反应式发布。
另请注意,由于一旦extraUserData
被标记为就绪,Meteor.user()
将发生变化,所有自动运行将重新运行两次:一次在登录用户首次加载时,一次在extraUserData
已加载。为避免这种情况,请改用Meteor.userId()
:它只会更改一次。
另请注意,在合并重叠记录集(游标)时,仅比较***值。这意味着,如果一个订阅包含a: x: 'x'
,而另一个订阅包含a: y: 'y'
(对于具有相同_id
的文档),那么客户端将不会像您预期的那样获得a: x: 'x', y: 'y'
,而是任意原件之一。请参阅this open issue,在this closed issue 中有更好的描述。【参考方案2】:
默认情况下,Meteor 用户仅发布其基本信息,因此您必须使用 Meteor.publish 手动将这些字段添加到客户端。值得庆幸的是,Meteor docs on publish 有一个示例向您展示如何执行此操作:
// server: publish the rooms collection, minus secret info.
Meteor.publish("rooms", function ()
return Rooms.find(, fields: secretInfo: 0);
);
// ... and publish secret info for rooms where the logged-in user
// is an admin. If the client subscribes to both streams, the records
// are merged together into the same documents in the Rooms collection.
Meteor.publish("adminSecretInfo", function ()
return Rooms.find(admin: this.userId, fields: secretInfo: 1);
);
基本上,您希望发布一个通道,该通道在满足条件时向客户端返回某些信息,而在不满足条件时返回其他信息。然后你在客户端订阅那个频道。
在您的情况下,您可能希望在服务器中使用这样的东西:
Meteor.publish("studentInfo", function()
var user = Meteor.users.findOne(this.userId);
if (user && user.type === "student")
return Users.find(_id: this.userId, fields: sessionsRemaining: 1, counselor: 1);
else if (user && user.type === "counselor")
return Users.find(_id: this.userId, fields: pricePerSession: 1);
);
然后在客户端订阅:
Meteor.subscribe("studentInfo");
【讨论】:
哎呀,我们重叠了。但是Meteor.user
在发布功能中不起作用。请参阅我的答案中的变体。
我的借口是我在它上面写了 // 伪代码!但你是对的 ;-)
如果用户类型/角色不是互斥的,这将如何工作? (我实际上简化了我的情况)。
我的意思是,假设您正在创建一个博客并且用户具有角色(评论版主、管理员、编辑),您可以成为其中的一种或多种。使用这些发布和订阅策略,我如何确保始终为当前用户发送信息,以及他们需要根据他们的所有角色看到的信息?
什么意思?您可以使用更多 if/else 语句扩展我为各种角色提供的示例代码。【参考方案3】:
因为 Meteor.users 是一个与任何其他 Meteor 集合一样的集合,所以您实际上可以像任何其他 Meteor 集合一样细化它的公开内容:
Meteor.publish("users", function ()
//this.userId is available to reference the logged in user
//inside publish functions
var _role = Meteor.users.findOne(_id: this.userId).role;
switch(_role)
case "counselor":
return Meteor.users.find(, fields: sessionRemaining: 0, counselor: 0 );
default: //student
return Meteor.users.find(, fields: counselorSpecific: 0 );
);
然后,在您的客户端中:
Meteor.subscribe("users");
因此,Meteor.user()
将根据登录用户的角色自动被截断。
这是一个完整的解决方案:
if (Meteor.isServer)
Meteor.publish("users", function ()
//this.userId is available to reference the logged in user
//inside publish functions
var _role = Meteor.users.findOne( _id: this.userId ).role;
console.log("userid: " + this.userId);
console.log("getting role: " + _role);
switch (_role)
case "counselor":
return Meteor.users.find(, fields: sessionRemaining: 0, counselor: 0 );
default: //student
return Meteor.users.find(, fields: counselorSpecific: 0 );
);
Accounts.onCreateUser(function (options, user)
//assign the base role
user.role = 'counselor' //change to 'student' for student data
//student specific
user.sessionRemaining = 100;
user.counselor = 'Sam Brown';
//counselor specific
user.counselorSpecific = studentsServed: 100 ;
return user;
);
if (Meteor.isClient)
Meteor.subscribe("users");
Template.userDetails.userDump = function ()
if (Meteor.user())
var _val = "USER ROLE IS " + Meteor.user().role + " | counselorSpecific: " + JSON.stringify(Meteor.user().counselorSpecific) + " | sessionRemaining: " + Meteor.user().sessionRemaining + " | counselor: " + Meteor.user().counselor;
return _val;
else
return "NOT LOGGED IN";
;
还有 html:
<body>
<div style="padding:10px;">
loginButtons
</div>
> home
</body>
<template name="home">
<h1>User Details</h1>
> userDetails
</template>
<template name="userDetails">
DUMP:
userDump
</template>
【讨论】:
以上是关于在 Meteor 中如何有条件地向客户端发送数据?的主要内容,如果未能解决你的问题,请参考以下文章