Standard query operations with .find() will not match two fields together in the way you are asking. You can get "close" results with standard match conditions, but actually having array elements compare is a little more advanced.
The "advanced swiss army knife" you are looking for comes in the form of the aggregation framework for MongoDB. This does a whole lot more than just "aggregate" data, as it is also the tool for general document manipulation and evaluation:
db.pop.aggregate([
// Match possible documents to reduce work
{ "$match": {
"people.age": { "$lt": 30 },
"countries.population": { "$gt": 100000000 }
}},
// Test the conditions against the arrays
{ "$project": {
"people": 1,
"countries": 1,
"match": {
"$anyElementTrue": {
"$map": {
"input": "$people",
"as": "p",
"in": {
"$anyElementTrue": {
"$map": {
"input": "$countries",
"as": "c",
"in": {
"$and": [
{ "$lt": [ "$$p.age",30 ] },
{ "$gt": [ "$$c.population",100000000 ] },
{ "$eq": [ "$$p.country", "$$c.name" ] }
]
}
}
}
}
}
}
}
}},
// Filter any documents that did not match
{ "$match": { "match": true }}
])
If you are after "filtering" those to just matching results then you can do this a little differently. I'll break up $project stages, but you could do it in one:
db.pop.aggregate([
// Match possible documents to reduce work
{ "$match": {
"people.age": { "$lt": 30 },
"countries.population": { "$gt": 100000000 }
}},
// Filter the people array for matches
{ "$project": {
"people": {
"$setDifference": [
{ "$map": {
"input": "$people",
"as": "p",
"in": {
"$cond": [
{ "$and": [
{ "$lt": [ "$$p.age", 30 ] },
{
"$anyElementTrue": {
"$map": {
"input": "$countries",
"as": "c",
"in": {
"$and": [
{ "$gt": [ "$$c.population", 100000000 ] },
{ "$eq": [ "$$p.country", "$$c.name" ] }
]
}
}
}
}
]},
"$$p",
false
]
}
}},
[false]
]
},
"countries": 1
}},
// Discard any document that did not meet conditions
{ "$match": { "people": { "$ne": false } }},
// Filter the countries to matching people
{ "$project": {
"people": 1,
"countries": {
"$setDifference": [
{ "$map": {
"input": "$countries",
"as": "c",
"in": {
"$cond": [
{ "$and": [
{ "$gt": [ "$$c.population", 100000000 ] },
{
"$anyElementTrue": {
"$map": {
"input": "$people",
"as": "p",
"in": {
"$eq": [ "$$p.country", "$$c.name" ]
}
}
}
}
]},
"$$c",
false
]
}
}},
[false]
]
}
}}
])
And in the second case you would get documents "filtered" of array elements that did not match like this:
{
"_id" : ObjectId("53c8f1645117367f5ff2036c"),
"people" : [
{
"name" : "Joseph",
"age" : 25,
"country" : "USA"
}
],
"countries" : [
{
"name" : "USA",
"population" : 300000000
}
]
}
Pretty powerful stuff.
Also see the aggregation framework operators and other aggregation samples in the documentation.
You can do similar things using mapReduce as well, but generally the aggregation framework is preferred as it is a native code implementation and MongoDB mapReduce relies on JavaScipt interpretation to run.