2012-05-11 9 views
0

私はexpressとmongoose/mongodbでnodejsアプリケーションを構築しています。Mongooseを使用したスキーマメソッドから埋め込みドキュメント(DBRefのような)の属性にアクセスするには?

ユーザーロール(ユーザーが0-nロールを持つ可能性があります)を管理するために、ユーザースキーマと別のロールスキーマを実装し、DBRefsのように結合し、簡単に他の。私は、これが「Xの役割を持つユーザーのリストを取得する」または「Yの役割がすぐに期限切れになるように設定されているユーザーのリストを取得する」のようなものに答える最善の方法だと考えたので、この構造を選択しました。

これらの役割とユーザーのための私のスキーマのバージョンのストリップダウンされています。これにより

RoleSchema = new Schema { 
    _user: { type: Schema.ObjectId, ref: 'User' } 
    type: String 
    expiration: { type: Date, default : '0' } 
} 

UserSchema = new Schema { 
    email: { type: String, index: { unique: true }}  
    roles : [{ type: Schema.ObjectId, ref: 'Role' }] 
} 

を、私は問題もなく私の急行スクリプト内からユーザーとロールを作成/フェッチ/移入することができています。ユーザーに役割を追加する場合は、役割を作成して保存し、ユーザーの役割配列にプッシュしてからユーザーを保存します。したがって、mongoDBでは、各スキーマには独自のコレクションがあり、idフィールドを介して互いにポイントしています。私は次何をしたいのか今

は、私は私ができることだろうと思った

if(user.isActiveSubscriber()) 

のようなものを行うことができるように、役割に関連する問題をチェックするために自分のスキーマにブール型のメソッドを実装しています

UserSchema.method "isActiveSubscriber", -> 
    result = false 
    now = new Date() 
    @roles.forEach (role) -> 
    result = true if role.type is "SUBSCRIBER" and role.expiration > now 
result 

私の問題は、ロールが空の属性で出てきていることです。これは、ユーザーのスキーマにメソッドを追加するだけです。ユーザーコレクションにはその役割のIDのみが含まれていますが、実際の属性は別のコレクションに格納されているので、意味があると思います。

だから、ここに質問に行く:

a)は、私のユーザー・スキーマのメソッド内から属性の役割をロードする方法はありますか? メソッド内でpopulateを呼び出そうとしましたが、ユーザーオブジェクトがpopulateメソッドを知らないというエラーが発生しました。私もメソッド内からRole.findById()を試してみましたが、エラー(RoleとRoleSchemaを試してみました)を受け取りました。

b)方法がない場合は、私のスクリプトで?この種のロジックをアプリケーションロジック/フローと混在させる必要はありません。より良い選択肢がありますか?

c)これらのコレクションを2つに分けるのは悪い考えですか? NoSQLの要点を完全に欠いていますか?ロールが単純にユーザーコレクションの一部として格納された埋め込みドキュメントの配列であれば、それは良いでしょうか?

答えて

1

あなたの質問にお答えします:

a)あなたの電話の中で役割を読み込むことができます。あなたは

Role = mongoose.model('Role', RoleSchema) 

をしたと仮定すると、あなただけの

Role.where('_id').in(user.roles).run((err, res) -> 
    /* you have roles in res now */ 
) 

これを実行する必要があることが、すなわち、あなたのメソッドに渡されるコールバックを必要とする、非同期操作ですユーザーuserのための今

UserSchema.method "isActiveSubscriber", (callback) -> 
    now = new Date() 
    if @roles.length is 0 
     return callback(false) 
    if @roles[0].type 
     /* roles are loaded, 
      maybe there is some other fancy way to do the check */ 
     result = false 
     @roles.forEach (role) -> 
      if role.type is "SUBSCRIBER" and role.expiration > now 
       result = true 
     callback(result) 
    else 
     /* we have to load roles */ 
     Role.where('_id').in(@roles).run((err, res) => 
      /* you have roles in res now */ 
      /* you may want to populate the field, 
       note => sign in this function definition */ 
      @roles = res 
      result = false 
      res.forEach (role) -> 
       if role.type is "SUBSCRIBER" and role.expiration > now 
        result = true 
      callback(result) 
     ) 

あなたが望むならば、問題は操作が非同期であり、それはあなたのコードに追加のコールバックのネストを強制すること(これは痛みになります。この

user.isActiveSubscriber((result) -> 
    /* do something with result */ 
) 

のようにそれを呼び出すことができます100人のユーザーの役割を確認するには、asyncのような非同期呼び出し処理ライブラリが必要です。だから、あなたがユーザーを読み込んで私たちに示したコードを使用するたびに、このフィールドに情報を入力するようアドバイスします。あなたは静的メソッドを追加することができます(デフォルトではfindメソッドをオーバーライドすることもできますか?これについてはわかりません)。

b + c)もう1つの選択肢は、あなたのコレクションに文字列として役割を格納し、app内に可能な役割をハードコードすることです。これは実装が簡単になりますが、新しい役割の追加/削除は$%^ & *の痛みになります。あなたがこれをやっているやり方(つまり参照を介して)はうまくいきます。あなたが必要とするのは、ユーザーを検索してすべてがうまくいくたびにフィールドにデータを入れることだけです。

+0

ありがとうございます。これを試みます。 –

0

採用されたアプローチは、人口を使用してDBRefのような動作を実装する方法の範囲内で採用されています。しかし、いくつかのことは忘れてしまったようです。これらの詳細が既に注意を払っていて、簡潔に表示されていないかどうかは不明です。

RoleSchema = new Schema { 
    type: String 
    expiration: { type: Date, default : '0' } 
} 

UserSchema = new Schema { 
    email: { type: String, index: { unique: true }}  
    _roles : [{ type: Schema.ObjectId, ref: 'Role' }] // array of pointers for roles 
} 

Role = mongo.model('Role', 'RoleSchema'); 
User = mongo.model('User', 'UserSchema'); 

var life_sub = new Role({ type: 'LIFE_SUBSCRIBER', .... }); 
var daily_sub = new Role({ type: 'DAILY_SUBSCRIBER', .... }); 
var monthly_sub = new Role({ type: 'MONTHLY_SUBSCRIBER', .... }); 

var jane = new User({email: '[email protected]', _roles: [daily_sub, monthly_sub]}); 

必要に応じてユーザーを追加します。指定されたユーザーとそれに対応するロールのセットを見つけるには、nextを使用します。ここで、userは指定されたユーザーの役割に対応するポインタの配列です。配列全体を繰り返し、ユーザーの役割と対応する有効期限を見つけます。 Date.now()と比較して、特定のユーザーに対してどのロールが期限切れになったのかを確認します。

これが役に立ちます。

+0

私のアプリケーションロジック内からpopulateを呼び出すと、正常に動作します。しかし、私はスキーマ関数からそれを行うより良い設計の決定だと思うので、私は与えられたユーザーの役割(例えば、セッション中の現在のユーザーのような)をチェックしたいときは、私は単純に行うことができます: if私のアプリケーションロジックと混在して、役割を検証するためにコードを記述する必要はありません。 –

関連する問題