web-dev-qa-db-ja.com

Mongoose-グループ化および設定方法

ODMとしてMongoDBとMongooseを使用しており、同じステートメントでpopulategroup byを使用してクエリを作成しようとしています。

これが私の簡単なドキュメントモデルです。

var userSchema = new Schema({
    username: String
});

var messageSchema = new Schema({
    from: { type: Schema.ObjectId, ref: 'User' },
    to: { type: Schema.ObjectId, ref: 'User' },
    message: String,
    date: { type: Date, default: Date.now }
});

私は、1人のユーザーのすべてのメッセージを取得しようとしています。ユーザーが会話するたびにグループ化します。私はこのようにしてみました:

this.find({ 'to': user })
    .sort({ 'date': 1 })
    .group('from')
    .populate(['from', 'to'])
    .exec(callback);

しかし、残念ながら、私のモデルにはgroupメソッドがありません。これを機能させるための解決策はありますか?

ありがとうございました。

17
Jeffrey Muller

$ lookup populateを使用した例では、lookupが配列として生成されるため、$ unwindになります。

Message.aggregate(
    [
        { "$match": { "to": user } },
        { "$sort": { "date": 1 } },
        { "$group": { 
            "_id": "from",
            "to": { "$first": "$to" },
            "message": { "$first": "$message" },
            "date": { "$first": "$date" },
            "origId": { "$first": "$_id" }
        }},
        { "$lookup": {
             "from": "users",
             "localField": "from",
             "foreignField": "_id",
             "as": "from"
        }},
        { "$lookup": {
             "from": "users",
             "localField": "to",
             "foreignField": "_id",
             "as": "to"
        }},
        { "$unwind": { "path" : "$from" } },
        { "$unwind": { "path" : "$to" } }
    ],
    function(err,results) {
        if (err) throw err;
        return results;
    }
)
19
raubas

ここで使用するより良いオプションは .aggregate() です。これは、MongoDBの .group() メソッドとは異なり、ネイティブコードの実装です。結果を処理するJavaScriptエンジン。

ただし、.populate()のようなメソッドは直接サポートされていません。これは、集約パイプラインおよび他のメソッドが現在のモデルのスキーマに基づく応答を厳密に返さないため、仕様によるものです。あなたがしていることを「想定」するのは間違っているので、単なる生のオブジェクト応答です。

ただし、応答をマングース文書として「キャスト」し、必要なパスで .populate() のモデル形式を呼び出すことを妨げるものはありません。

_Message.aggregate(
    [
        { "$match": { "to": user } },
        { "$sort": { "date": 1 } },
        { "$group": { 
            "_id": "from",
            "to": { "$first": "$to" },
            "message": { "$first": "$message" },
            "date": { "$first": "$date" },
            "origId": { "$first": "$_id" }
        }}
    ],
    function(err,results) {
        if (err) throw err;
        results = result.map(function(doc) { 
            doc.from = doc._id
            doc._id = doc.origId;
            delete doc.origId;
            return new Message( doc ) 
        });
        User.populate( results, { "path": "from to" }, function(err,results) {
            if (err) throw err;
            console.log( JSON.stringify( results, undefined, 4 ) );
        });
    }
)
_

もちろん、それは実際には、演算子によって暗示されるように、各「from」から _$first_ メッセージを返すだけです。 。

「group by」が本当に意味することは、実際には「ソート」です。

_Message.find({ "to": user })
    .sort({ "from": 1, "date": 1 })
    .populate("from to")
    .exec(function(err,messsages) {
        if (err) throw err;
        console.log( JSON.stringify( messages, undefined, 4 ) );
    });
_

コンテキストが「すべてのメッセージ」を示しており、.aggregate().group()コレクションメソッドなどのグループ化演算子によって暗示されるものではありません。したがって、メッセージは、特定のグループ化ではなく、ソートによって「グループ化」されます。

後者はあなたが本当に求めているもののように聞こえますが、実際に「グループ化」を意図している場合は、.populate()を使用する方法とともに集約の例があります。

12
Neil Lunn