次のように定義された2つのスキーマがあります。
var WorksnapsTimeEntry = BaseSchema.extend({
student: {
type: Schema.ObjectId,
ref: 'Student'
},
timeEntries: {
type: Object
}
});
var StudentSchema = BaseSchema.extend({
firstName: {
type: String,
trim: true,
default: ''
// validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: ''
// validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
},
municipality: {
type: String
}
});
そして、私は各学生をループして、それが時間エントリであることを示したいと思います。これまでのところ、WorksnapTimeEntryスキーマテーブルにどのように参加すればよいかまだわからないため、明らかに正しくないこのコードがあります。
Student.find({ status: 'student' })
.populate('student')
.exec(function (err, students) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
}
_.forEach(students, function (student) {
// show student with his time entries....
});
res.json(students);
});
私はそのようなことをどのように達成するのか知っていますか?
ここでは.populate()
は必要ありませんが、代わりに2つのクエリが必要です。最初のクエリはStudent
オブジェクトに一致して__id
_値を取得し、2番目のクエリは _$in
_ これらの「生徒」のそれぞれのWorksnapsTimeEntry
アイテムに一致します。
インデントのクリープを避けるためだけに _async.waterfall
_ を使用する:
_async.waterfall(
[
function(callback) {
Student.find({ "status": "student" },{ "_id": 1 },callback);
},
function(students,callback) {
WorksnapsTimeEntry.find({
"student": { "$in": students.map(function(el) {
return el._id
})
},callback);
}
],
function(err,results) {
if (err) {
// do something
} else {
// results are the matching entries
}
}
)
_
本当に必要な場合は、2番目のクエリで.populate("student")
を使用して、他のテーブルからアイテムを取得できます。
逆の場合は、WorksnapsTimeEntry
でクエリを実行して「すべて」を返し、「match」クエリオプションを使用して.populate()
からのnull
の結果を除外します。
_WorksnapsTimeEntry.find().populate({
"path": "student",
"match": { "status": "student" }
}).exec(function(err,entries) {
// Now client side filter un-matched results
entries = entries.filter(function(entry) {
return entry.student != null;
});
// Anything not populated by the query condition is now removed
});
_
「データベース」は結果の大部分をフィルタリングしないため、これは望ましいアクションではありません。
そうしない正当な理由がない限り、データを「埋め込む」必要があります。そうすれば、_"status
_ "のようなプロパティは既にコレクションで利用でき、追加のクエリは必要ありません。
MongoDBのようなNoSQLソリューションを使用している場合、リレーショナル設計の原則に固執するのではなく、その概念を採用する必要があります。リレーショナルモデリングを一貫して行っている場合は、リレーショナルデータベースを使用することもできます。それを処理する他の方法を備えたソリューションから利益を得ることはないからです。
バージョン3.2では、集約パイプラインで $ lookup を使用して、左外部結合を実行できます。
Student.aggregate([{
$lookup: {
from: "worksnapsTimeEntries", // collection name in db
localField: "_id",
foreignField: "student",
as: "worksnapsTimeEntries"
}
}]).exec(function(err, students) {
// students contain WorksnapsTimeEntries
});