1

私は(Mongooseを使用して)照会している「アクティビティ」と呼ばれるモデルを持っています。それらのスキーマは次のようになります。

var activitySchema = new mongoose.Schema({
    actor: {
        type: mongoose.Schema.ObjectId,
        ref: 'User',
        required: true
    },
    recipient: {
        type: mongoose.Schema.ObjectId,
        ref: 'User'
    },
    timestamp: {
        type: Date, 
        default: Date.now
    },
    activity: {
        type: String,
        required: true
    },
    event: {
        type: mongoose.Schema.ObjectId,
        ref: 'Event'
    },
    comment: {
        type: mongoose.Schema.ObjectId,
        ref: 'Comment'
    }
});

それらを照会するとactor、 、recipientevent、およびcommentフィールド (すべての参照) にデータが入力されます。その後、取得するeventフィールドにもディープ ポピュレートしますevent.creator。クエリのコードは次のとおりです。

var activityPopulateObj = [
                { path: 'event' },
                { path: 'event.creator' },
                { path: 'comment' },
                { path: 'actor' },
                { path: 'recipient' },
                { path: 'event.creator' }
            ],
            eventPopulateObj = {
                path: 'event.creator',
                model: User
            };

Activity.find({ $or: [{recipient: user._id}, {actor: {$in: user.subscriptions}}, {event: {$in: user.attending}}], actor: { $ne: user._id} })
            .sort({ _id: -1 })
            .populate(activityPopulateObj)
            .exec(function(err, retrievedActivities) {
                if(err || !retrievedActivities) {
                    deferred.reject(new Error("No events found."));
                }
                else {
                    User.populate(retrievedActivities, eventPopulateObj, function(err, data){
                        if(err) {
                            deferred.reject(err.message);
                        }
                        else {
                            deferred.resolve(retrievedActivities);
                        }
                    });
                }
            });

これはすでに比較的複雑なクエリですが、さらに多くのことを行う必要があります。$orというステートメントの部分にヒットした場合は{actor: {$in: user.subscriptions}}、'sフィールドが文字列と等しいこと確認する必要があります。を使用してみましたが、最初にイベントを入力する必要があるため、そのフィールドを照会できませんでした。他の複数のクエリでも同じ目標を達成する必要があります。eventprivacypublic$elemMatch

私が説明したように、このさらなるフィルタリングを実現する方法はありますか?

4

3 に答える 3

8

答えは、スキーマを変更することです。

あなたは、リレーショナル データベースを使用してきた歴史からドキュメント データベースの開発を始める際に、多くの開発者が経験する罠に陥っています。MongoDB はリレーショナル データベースではなく、リレーショナル データベースのように扱われるべきではありません。

外部キーと完全に正規化されたデータについて考えるのをやめ、代わりに各ドキュメントを可能な限り自己完結型に保ち、関連する関連データをドキュメント内に埋め込む最適な方法を考える必要があります。

これは、関連付けも維持できないという意味ではありません。必要な詳細のみを埋め込み、必要に応じて完全なレコードを照会する、次のような構造を意味する場合があります。

var activitySchema = new mongoose.Schema({
  event: {
    _id: { type: ObjectId, ref: "Event" },
    name: String,
    private: String
  },

  // ... other fields
});

埋め込み戦略を再考すると、クエリが大幅に簡素化され、クエリ数が最小限に抑えられます。 populateデータセットが大きくなると、これが問題になる可能性が非常に高くなります。

于 2013-10-24T18:35:13.833 に答える
0

しかし、最初にイベントにデータを入力する必要があるため、どのフィールドにもクエリを実行できませんでした。

いいえ、できません。Mongodb は結合を実行できません。クエリを作成すると、一度に 1 つのコレクションだけを操作できます。参考までに、これらすべてのマングース ポピュレートは、それらのレコードをロードするための追加の個別のデータベース クエリです。

スキーマとアプリケーションの詳細を掘り下げる時間はありませんが、おそらく、データを非正規化し、参加する必要があるイベント フィールドのコピーをプライマリ コレクションに保存する必要があります。

于 2013-10-24T17:49:09.153 に答える