0

expressとmongoose/mongodbを使用してnodejsアプリを構築しています。

ユーザーの役割(ユーザーは0からnの役割を持つ場合があります)を管理するために、ユーザースキーマと個別の役割スキーマを実装し、DBRefのようにそれらを結び付け、マングースの入力機能を使用して一方から他方に簡単に移動することにしました。この構造を選択したのは、「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のポイントを完全に見逃していますか?ロールがユーザーコレクションの一部として保存された埋め込みドキュメントの配列であるとしたら、もっと良いでしょうか?

4

2 に答える 2

1

あなたの質問に答えさせてください:

a)できることは、通話内に役割をロードすることです。あなたがしたと仮定して

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

あなたはただ走る必要があります

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

ただし、これは非同期操作であり、コールバックをメソッドに渡す必要があります。

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ように呼び出すことができます

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

問題は、操作が非同期であり、コードに追加のコールバックネストを強制することです(たとえば、100人のユーザーのロールを確認する場合は、asyncなどのライブラリを処理する非同期呼び出しが必要になります)。したがって、ユーザーをロードして、表示されたコードを使用するたびに、このフィールドにデータを入力することをお勧めします。これに静的メソッドを追加できます(デフォルトのメソッドをオーバーライドすることもできますfindか?これについてはよくわかりませんが)。

b + c)もう1つのオプションは、ロールをコレクションに文字列として保存し、アプリで可能なロールをハードコーディングすることです。これは実装が簡単になりますが、新しい役割の追加/削除は$%^&*の苦痛になります。これを行う方法(つまり、参照を介して)は問題ありません。必要なのは、ユーザーを検索するたびにフィールドに入力することだけで、すべてがうまくいくと思います。

于 2012-05-11T14:35:08.103 に答える
0

採用されたアプローチは、mongooseがpopulateを使用して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: 'jane@ab.com', _roles: [daily_sub, monthly_sub]});

必要に応じてユーザーを追加します。次に、指定されたユーザーを検索し、対応するロールのセットを使用します。

User
 .find({email:'jane@ab.com'})
 .populate('_roles[]')
 .run(function(err, user)

これで、userは、指定されたユーザーの役割に対応するポインターの配列になります。アレイを反復処理して、ユーザーの各役割と対応する有効期限を見つけます。Date.now()と比較して、特定のユーザーの役割の有効期限が切れているかどうかを確認します。

お役に立てれば。

于 2012-05-11T15:29:23.043 に答える