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.
I couldn't find a way to achieve this through mongoose queries, but I think it works using the MongoDB aggregation pipeline
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'}}
]);
$lookup
acts like .populate()
, replacing the reference with the actual data. It returns an array though since it can be used to match multiple documents.
$unwind
removes items from an array, and in this case will just turn the single element array into a field.
$match
then 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.
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.
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.