在匹配数组时,MongoDB 中的投影只能在“顶级”数组级别工作。要在“服务器”上做更多的事情,您需要使用“聚合框架”,它比标准的.find() 查询更擅长做这件事:
Model.aggregate(
[
// Match the document(s) that contain this match
{ "$match": { "users.companies.dept.id": "10" } },
{ "$project": {
"users": {
"$setDiffernce": [
{ "$map": {
"input": "$users",
"as": "user",
"in": {
"$setDifference": [
{ "$map": {
"input": "$$user.companies",
"as": "comp",
"in": {
"$cond": [
{ "$eq": [ "$$comp.dept.id", "10" ] },
"$comp",
false
]
}
}},
[false]
]
}
}},
[[]]
]
}
}}
],
function(err,results) {
}
);
这将“剥离”任何不匹配的元素和任何生成的“空”数组,因为其中没有匹配的元素。只要包含的元素在它们的组合属性中都是“唯一的”,它通常是安全的。
它也非常快,由于仅包含 $match 和 $project 阶段,因此与标准 .find() 操作一样快。这基本上就是.find() 所做的。所以除了“一点”额外的过度外,没有什么区别。当然,每次比赛从服务器返回的流量更少。
如果您的 MongoDB 服务器版本低于 2.6 而没有这些运算符,或者如果您的“dept.id”值在内部数组中不是唯一的,您也可以这样做。
Model.aggregate(
[
// Match the document(s) that contain this match
{ "$match": { "users.companies.dept.id": "10" } },
// Unwind arrays
{ "$unwind": "$users" },
{ "$unwind": "$users.companies" },
// Match to "filter" the array
{ "$match": { "users.companies.dept.id": "10" } },
// Group back to company
{ "$group": {
"_id": {
"_id": "$_id",
"user_id": "$user._id",
"userEmail": "$user.email"
},
"companies": { "$push": "$users.companies" }
}},
// Now push "users" as an array
{ "$group": {
"_id": "$_id._id",
"users": { "$push": {
"_id": "$_id.userId",
"email": "$_id.userEmail",
"companies": "$companies"
}}
}}
],
function(err,results) {
}
);
但是$unwind 的所有使用对于性能来说都是很糟糕的,您最好像现在一样简单地删除应用程序代码中不需要的项目。
因此,如果您的服务器支持它,那么请使用第一个选项来减轻您的应用程序和网络传输的负担。否则坚持你正在做的事情,因为它可能会更快。