我有3个架构,如下所示:
用户
var UserSchema = new Schema({
name: String
});
演员
var ActorSchema = new Schema({
name: String
});
评分
var RatingSchema = new Schema({
actor: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Actor'
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Actor'
},
userRating: Number
});
我想将所有演员信息发送到前端,如[actor1,actor2 ...]。 每个演员都包含演员的详细信息和' userRating'这是由当前登录的用户提供的。 用户可以向多个演员提供评级,演员可以从多个用户接收评级。这些将存储在评级表中。
我写了这样的东西
Actor
.find({}) // get all actors and populate userRating into each actor
.populate({
path: 'userRating',
model: 'Rating',
match: { actor: {$eq: req.actor}, user: {$eq: req.user}},
select: 'userRating'
})
.exec(function(error, actors){
if(error)
res.status(501).json({error: error});
else
res.json(actors);
});
我在结果中只有演员。演员对象不包含' userRating'。有人可以更正我的查询
答案 0 :(得分:1)
这取决于您实际发送的内容作为查询参数的输入。另外你需要了解的主要事情是不 a" JOIN",实际上是由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
操作来执行" JOINS"在"服务器"代替:
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)