2012-12-28 10 views
7

条件付きでクライアントにデータを送信する方法を把握しようとしています。meteorです。私は2つのユーザータイプがあり、ユーザーのタイプに応じて、クライアント上のインターフェイス(したがって、必要なデータが異なります)。Meteorではどのように条件付きでクライアントにデータを送信しますか?

ユーザーのタイプがcounselorまたはstudentであるとします。すべてのユーザ文書はrole: 'counselor'またはrole: 'student'のようなものです。どのように私は、クライアント側のMeteor.user()が、私は必要な情報を持っており、どれも余分なことを確認してしまう

など、

学生はsessionsRemainingcounselorなどの学生の特定の情報を持っている、とカウンセラーがpricePerSessionのようなものがありますか?学生としてログインしている場合、Meteor.user()にはsessionsRemainingcounselorが含まれている必要がありますが、私はカウンセラーとしてログインしていません。私が探しているのは、条件付きの出版物と流星群のサブスクリプションです。

+0

私は今、いくつかの回答を得ていると私は、私は彼らので最高のを選択する方法を知っているかわかりませんすべてが表面上で動作するようです。私はもっ​​と複雑な状況(つまり、役割が相互に排他的でない時など)のために働く最も単純な、最も「流星」のバージョンを望みたいと思う。 – Diogenes

+0

その場合、彼はおそらく@ debergalisの答えをクリエイターの一人だから選ぶべきだろう流星のそれよりずっと多くの流星を得られない:) – Rahul

答えて

13

は、フィールドのみを返すように分野オプションを使用しますあなたは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.usersコレクション内のドキュメントは、2つのフィールドセットの和集合になります。あなたのクライアントに、

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.usersは、他の流星のコレクションなどのコレクションがあるので

+2

微妙な注意点:ユーザーの役割が動的に変更される可能性がある場合、このパブリッシャーは気付かずにパブリッシュするフィールドを変更します。このようなことをする必要がある場合、現在は 'observe'の上に手動で実装する必要があります。うまくいけば、将来的にはMeteorは完全に反応的な公開を行うための何らかの方法を持っています。 –

+0

'extraUserData'が準備完了とマークされると' Meteor.user() 'が変更されるので、すべてのAutorunsは2回再実行されます:ログインしたユーザーが最初にロードされたときと' extraUserData'がロードされたとき。これを避けるには、代わりに 'Meteor.userId()'を使います:一度だけ変更されます。 –

+0

重複するレコードセット(カーソル)をマージするときは、トップレベルの値のみを比較します。これは、あるサブスクリプションに '{a:{x: 'x'}}'が含まれていて、別のサブスクリプションに '{a:{y: 'y'}}'(同じ '_id'を持つドキュメントの場合) **あなたが期待しているように '{a:{x: 'x'、y: 'y'}}を取得するのではなく、オリジナルの任意のものを取得する。 [こちらの未公開の問題](https://github.com/meteor/meteor/issues/3764)を参照してください。これについては、この[閉鎖された問題](https://github.com/meteor/meteor/issues/903)を参照してください。 – BudgieInWA

3

デフォルトで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"); 
+1

うわー、私たちは重なった。しかし、 'Meteor.user'はパブリッシュ関数では機能しません。私の答えの変種を見てください。 – debergalis

+0

私の言い訳は、私は//それの上に擬似コードを書いたことです!しかし、あなたは正しい;-) – Rahul

+1

私は物事を編集することができます忘れる。修正済み: – debergalis

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> 
関連する問題