2017-12-06 13 views
1

私は新しい仮想母集団機能を使用する(Mongoose 4.13、Mongo 3.6を使用して)Mongooseスキーマで集約をしようとしています。モンゴース仮想母集団と集計

const ProjectSchema = new mongoose.Schema({ 
    projectId: Number, 
    description: String 
}); 

ProjectSchema.virtual('tasks', { 
    ref: 'Task', 
    localField: 'projectId', 
    foreignField: 'projectId' 
    justOne: false 
]); 

const TaskSchema = new mongoose.Schema({ 
    taskId: Number, 
    projectId: Number 
    hours: Number 
}); 

const Project = mongoose.model('Project', ProjectSchema); 
const Task = mongoose.model('Task', TaskSchema); 

プロジェクトに照会し、関連するタスクを移入が.populateを使用して正常に動作している()のように:

は、私は、スキーマ(説明のために簡略化)次ているとしましょう

Project.find({projectId: <id>}).populate('tasks'); 

しかし、今私はプロジェクトごとにタスクの時間を合計したいと思います($ sumの部分をbtw ..の下に残しました)。私は何があっても空の配列を返すだけです。バーチャルポピュレートと集約することはできませんか?

const result = await Project.aggregate([ 
    { $match : { projectId: <id> } }, 
    { $lookup: { 
     from: 'tasks', 
     localField: 'projectId', 
     foreignField: 'projectId', 
     as: 'tasks' 
    }, 
    { 
     $unwind: '$tasks' 
    } 
    } 
]); 

答えて

0

ため、仮想移入は、総計では動作しません「返されたドキュメントは、プレーンJavaScriptのオブジェクトである(文書の任意の形状を返すことができるので)、文書をマングースない。」ドキュメント(c)において、より多くの情報 - Mongoose aggregate

+0

うーん..私はhttps://stackoverflow.com/questions/46472643/how-to-aggregate-when-using-populate([SO質問]この沿って来ました-virtuals-in-mongoose)ここでは、$ popupとvirtual populateを使用する方法について説明します。それについての考えは? – Ramon

0

Model.aggregateためのマングースのマニュアル参照:$プロジェクト事業者は文書を残す可能性がある、パイプラインのいずれかの段階でのドキュメントの「形状」を再定義できるための引数は、モデルのスキーマにキャストされていない

を私は互換フォーマット。

本質的に、これは、マングースを使用してスキーマを使用して許可されているもののマジックを意味します。実際には、aggregation(特に$lookup)のMongoDBのドキュメントを直接参照する必要があります。

const ProjectSchema = new mongoose.Schema({ 
    projectId: Number, 
    description: String 
}); 

const TaskSchema = new mongoose.Schema({ 
    taskId: Number, 
    projectId: Number, 
    hours: Number 
}); 

const Project = connection.model('Project', ProjectSchema); 
const Task = connection.model('Task', TaskSchema); 

const project1 = new Project({ projectId: 1, description: 'Foo'}); 
const project2 = new Project({ projectId: 2, description: 'Foo'}); 
const task1 = new Task({ task: 1, projectId: 1, hours: 1}); 
const task2 = new Task({ task: 2, projectId: 1, hours: 2}); 
const task3 = new Task({ task: 3, projectId: 2, hours: 1}); 

Promise.all([ 
    project1.save(), 
    project2.save(), 
    task1.save(), 
    task2.save(), 
    task3.save() 
]).then(() => { 
    return Project.aggregate([ 
    { $match: { projectId: 1 }}, 
    { 
     $lookup: { 
     from: 'tasks', 
     localField: 'projectId', 
     foreignField: 'projectId', 
     as: 'tasks' 
     } 
    } 
    ]).exec(); 
}).then((result) => { 
    console.dir(result, { depth: null, color: true }); 
}); 

出力以下:

[{ 
    _id: ObjectID {/*ID*/}, 
    projectId: 1, 
    description: 'Foo', 
    __v: 0, 
    tasks: [{ 
     _id: ObjectID {/*ID*/}, 
     projectId: 1, 
     hours: 2, 
     __v: 0 
    }, 
    { 
     _id: ObjectID {/*ID*/}, 
     projectId: 1, 
     hours: 1, 
     __v: 0 
    } 
    ] 
}] 

しかし、あなたは頼むかもしれない:「それは私がなるように作業を行う理由を持っている基本的には何ですか」

サンプルコードがコピー/ペーストされているかどうかはわかりませんが、例では$unwindステージがパイプラインの第2ステージ($lookup)に誤って含まれているようです。次のコードが示すように、それを第3段階として追加すると、出力は図のように変更されます。

return Project.aggregate([ 
    { $match: { projectId: 1 }}, 
    { 
    $lookup: { 
     from: 'tasks', 
     localField: 'projectId', 
     foreignField: 'projectId', 
     as: 'tasks' 
    } 
    }, 
    { $unwind: '$tasks' } 
]).exec(); 

出力:

[{ 
    _id: ObjectID {/*ID*/}, 
    projectId: 1, 
    description: 'Foo', 
    __v: 0, 
    tasks: { 
     _id: ObjectID {/*ID*/}, 
     projectId: 1, 
     hours: 1, 
     __v: 0 
    } 
    }, 
    { 

    _id: ObjectID {/*ID*/}, 
    projectId: 1, 
    description: 'Foo', 
    __v: 0, 
    tasks: { 
     _id: ObjectID {/*ID*/}, 
     projectId: 1, 
     hours: 2, 
     __v: 0 
    } 
    } 
] 
+0

ありがとう、非常に感謝します。私が持っていた問題が見つかりました。私はコレクションを区別しやすくするために、自分のスキーマにカスタム定義のコレクション名を使用します。私の場合は同じではないスキーマ名を参照しようとしていましたが、$ lookup集約の 'from'フィールドはコレクション名を指定しています。今はうまくいきます! – Ramon