Как вы условно отправляете данные клиенту в Метеор?
Я пытаюсь выяснить, как условно отправить данные клиенту в метеоре. У меня есть два типа пользователей, и в зависимости от типа пользователя их интерфейсы на клиенте (и, следовательно, данные, которые им требуются, различны).
Допустим, пользователи имеют тип counselor
или же student
, Каждый пользовательский документ имеет что-то вроде role: 'counselor'
или же role: 'student'
,
Студенты имеют конкретную информацию о студентах, как sessionsRemaining
а также counselor
и у консультантов есть такие вещи, как pricePerSession
, так далее.
Как бы я убедиться, что Meteor.user()
на стороне клиента есть информация, которая мне нужна, и ничего лишнего? Если я вошел как студент, Meteor.user()
должны включать sessionsRemaining
а также counselor
, но не в том случае, если я вошел как консультант. Я думаю, что я могу искать условные публикации и подписки в терминах метеора.
3 ответа
Используйте параметр 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.users
коллекция будет объединением двух наборов полей.
Пользователи Meteor по умолчанию публикуются только со своей основной информацией, поэтому вам придется вручную добавлять эти поля к клиенту с помощью Meteor.publish. К счастью, в документации по публикации Meteor есть пример, который показывает вам, как это сделать:
// 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.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>