Как объединить две коллекции в mongoose
у меня есть две схемы, как указано ниже:
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);
});
кто-нибудь знает, как мне этого достичь?
2 ответов
не хочешь .populate()
здесь, но вместо этого вы хотите два запроса, где первый соответствует Student
объекты, чтобы получить _id
ценностей, а второй будет использовать $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
}
}
)
если вы действительно должны, то вы можете .populate("student")
на втором запросе, чтобы получить заполненные элементы из другого таблица.
обратный случай заключается в запросе на WorksnapsTimeEntry
и верните "все", затем отфильтруйте любые null
результаты .populate()
с опцией запроса "match":
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
" уже доступны на сбор и дополнительные запросы не требуются.
если вы используете решение NoSQL, такое как MongoDB, вы должны охватывать его концепции, а не придерживаться принципов реляционного дизайна. Если вы последовательно моделируете отношения, вы можете также использовать реляционную базу данных, так как вы не получите никакой выгоды от решения, которое имеет другие способы справиться с этим.
начиная с версии 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
});