node.js Mongoose 按引用模型的字段对模型进行嵌套查询
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19380738/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mongoose nested query on Model by field of its referenced model
提问by AzaFromKaza
It seems like there is a lot of Q/A's on this topic on stackoverflow, but I can't seem to find an exact answer anywhere.
似乎在 stackoverflow 上有很多关于这个主题的问答,但我似乎无法在任何地方找到确切的答案。
What I have:
我拥有的:
I have Company and Person models:
我有 Company 和 Person 模型:
var mongoose = require('mongoose');
var PersonSchema = new mongoose.Schema{
name: String,
lastname: String};
// company has a reference to Person
var CompanySchema = new mongoose.Schema{
name: String,
founder: {type:Schema.ObjectId, ref:Person}};
What I need:
我需要的:
Find all companies that people with lastname "Robertson" have founded
查找姓氏为“Robertson”的人创立的所有公司
What I tried:
我试过的:
Company.find({'founder.id': 'Robertson'}, function(err, companies){
console.log(companies); // getting an empty array
});
Then I figured that Person is not embedded but referenced, so I used populate to populate founder-Person and then tried to use find with 'Robertson' lastname
然后我认为 Person 没有被嵌入而是被引用,所以我使用 populate 来填充创始人-Person,然后尝试使用带有“Robertson”姓氏的 find
// 1. retrieve all companies
// 2. populate their founders
// 3. find 'Robertson' lastname in populated Companies
Company.find({}).populate('founder')
.find({'founder.lastname': 'Robertson'})
.exec(function(err, companies) {
console.log(companies); // getting an empty array again
});
I still can query companies with Person's id as a String. But it's not exactly what I want as you can understand
我仍然可以使用 Person 的 id 作为字符串查询公司。但这并不完全是我想要的,正如你所理解的
Company.find({'founder': '525cf76f919dc8010f00000d'}, function(err, companies){
console.log(companies); // this works
});
回答by JohnnyHK
You can't do this in a single query because MongoDB doesn't support joins. Instead, you have to break it into a couple steps:
您不能在单个查询中执行此操作,因为 MongoDB 不支持连接。相反,您必须将其分解为几个步骤:
// Get the _ids of people with the last name of Robertson.
Person.find({lastname: 'Robertson'}, {_id: 1}, function(err, docs) {
// Map the docs into an array of just the _ids
var ids = docs.map(function(doc) { return doc._id; });
// Get the companies whose founders are in that set.
Company.find({founder: {$in: ids}}, function(err, docs) {
// docs contains your answer
});
});
回答by sbrass
I'm pretty late to this one :p But I was just searching for a similar answer and I thought I'd share what I came up with in case anyone finds this for the same reason.
我已经很晚了 :p 但我只是在寻找一个类似的答案,我想我会分享我的想法,以防有人出于同样的原因发现这个。
I couldn't find a way to achieve this through mongoose queries, but I think it works using the MongoDB aggregation pipeline
我找不到通过猫鼬查询来实现这一点的方法,但我认为它可以使用MongoDB 聚合管道
To get the query you're looking for you could do something like this:
要获得您正在寻找的查询,您可以执行以下操作:
const result=await Company.aggregate([
{$lookup: {
from: 'persons',
localField: 'founder',
foreignField: '_id',
as: 'founder'}
},
{$unwind: {path: '$founder'}},
{$match: {'founder.lastname', 'Robertson'}}
]);
$lookupacts like .populate(), replacing the reference with the actual data. It returns an array though since it can be used to match multiple documents.
$lookup就像.populate(),用实际数据替换引用。它返回一个数组,因为它可用于匹配多个文档。
$unwindremoves items from an array, and in this case will just turn the single element array into a field.
$unwind从数组中删除项目,在这种情况下,只会将单个元素数组转换为字段。
$matchthen does what it sounds like and only returns documents matching the query. You can also do more complex matching than strict equality if you need.
$match然后做它听起来像的事情,只返回与查询匹配的文档。如果需要,您还可以进行比严格相等更复杂的匹配。
In general the way the aggregation pipeline works is by continually filtering/modifying matching documents each step of the way until you have just what you want.
一般来说,聚合管道的工作方式是在每一步中不断过滤/修改匹配的文档,直到你得到你想要的。
I haven't checked the performance on this, but I definitely prefer having Mongo do the work rather than filtering out unnecessary results server side.
我还没有检查过这方面的性能,但我绝对更喜欢让 Mongo 来做这项工作,而不是过滤掉不必要的结果服务器端。
I guess the only downside is that the result will be just an array of objects rather than mongoose models since the pipeline typically changes the shape of documents. So you won't be able to use the model's methods on the returned data.
我想唯一的缺点是结果将只是一个对象数组而不是猫鼬模型,因为管道通常会改变文档的形状。因此,您将无法对返回的数据使用模型的方法。
回答by evanmcd
In case anyone comes across this in more recent times, Mongoose now supports join like functionality with a feature called Populate.
万一有人在最近遇到过这种情况,Mongoose 现在支持使用名为 Populate 的功能加入类似功能。
From the Mongoose documentation:
从猫鼬文档:
Story.findOne({
title: 'Casino Royale'
}).populate('author').exec(function (err, story) {
if (err) return handleError(err);
console.log('The author is %s', story.author.name);
// prints "The author is Ian Fleming"
});

