Это зависит от того, что вы фактически отправляете в качестве входных данных для параметров запроса здесь. Кроме того, главное, что вам нужно понять, это то, что это не «СОЕДИНЕНИЕ», а фактически отдельные запросы, отправляемые mongoose
программным уровнем, поэтому существуют явные различия в обработке.
В базовом случае, когда "значения", предоставляемые в качестве параметров, на самом деле являются ObjectId
значениями ссылок, тогда вы фактически просто хотите, чтобы они были непосредственно в основном "запросе", а не аргументами для действия .populate()
(что на самом деле является тем местом, где "дополнительные запросы "происходят).
Кроме того, ваши «отношения / ссылки» находятся в модели Rating
, поэтому вместо этого выдается ваш запрос:
Rating.find({
"actor": req.actor,
"user": req.user
}).populate("actor user").exec(function(err,ratings) {
// Matched ratings by actor and user supplied
})
Если вместо этого ваши параметры представляют собой "name"
данные каждого объекта, то, поскольку эта информация отсутствует в модели Rating
до тех пор, пока она не будет заполнена, единственный способ mongoose
сделать это - получить «все» из Rating
объектов, а затем выполнить «заполнение» с помощью критериям "match"
и, наконец, отфильтровать любые результаты, где совокупность была null
из-за несоответствующих элементов:
Rating.find().populate([
{ "path": "actor", "match": { "name": req.actor } },
{ "path": "user", "match": { "name": req.user } }
]).exec(function(err,ratings) {
// Now filter out the null results
ratings = ratings.filter(function(rating) {
return ( rating.actor != null && rating.user != null )
});
// Then work with filtered data
})
Конечно, это очень неэффективно, поскольку это операция на стороне клиента, и вы втягиваете весь Rating
контент «первым». Итак, что вы на самом деле собираетесь сделать в этом случае, так это выполнить «три» операции запроса самостоятельно и получить значения ObjectId
из моделей User
и Actor
, чтобы вместо этого применить сопоставление к модели Rating
:
async.parallel(
{
"user": function(callback) {
User.findOne({ "name": req.user },callback)
},
"actor": function(callback) {
Actor.findOne({ "name": req.actor },callback)
}
},
function(err,data) {
// Use returned _id values in query
Rating.find({
"actor": data.actor._id,
"user": data.user._id
}).populate("actor user").exec(err,ratings) {
// populated Rating results
});
}
)
Затем запросы разрешают «только» ObjectId
значения, которые вам действительно нужны, а последний запрос Rating
извлекает только те результаты, которые действительно соответствуют условиям, а не все и выполняет операцию «пост-фильтра».
В качестве последнего подхода, если у вас есть MongoDB 3.2, вы можете альтернативно использовать $lookup
вместо выполнения операции "СОЕДИНЕНИЯ" на "сервере":
Rating.aggregate(
[
{ "$lookup": {
"from": "users",
"localField": "user",
"foreignField": "_id",
"as": "user"
}},
{ "$unwind": "$user" },
{ "$match": { "user.name": req.user } },
{ "$lookup": {
"from": "actors",
"localField": "actor",
"foreignField": "_id",
"as": "actor"
}},
{ "$unwind": "actor" },
{ "$match": { "actor.name": req.actor } }
],
function(err,ratings) {
// populated on the server in one request
}
)
С точки зрения «клиента», это всего лишь «один» запрос и ответ в отличие от того, что делает .populate()
. Но на самом деле это не более чем «серверная» интерпретация «клиентской» логики, представленной ранее.
Поэтому при поиске по значениям "name"
вы должны вместо этого использовать подход «три» для оптимальной производительности, поскольку версия агрегирования все еще действительно работает с гораздо большим количеством данных, чем нужно.
Конечно, «лучшая» перспектива - просто использовать для начала значения ObjectId
.
Конечно, главное здесь то, что такая информация, как "userRating"
, принадлежит модели Rating
, и поэтому вы предоставляете «запрос» во всех случаях для получения этих данных. Это не операции «JOIN», как в SQL, поэтому «сервер» не смотрит на объединенные результаты, а затем выбирает поля.
В качестве небольшого самообразования включите «отладку», чтобы увидеть, как mongoose
фактически отправляет операторы серверу. Тогда вы увидите, как на самом деле применяется .populate()
:
mongoose.set("debug",true)
person
Neil Lunn
schedule
18.04.2016