使用
.find()
的标准查询操作无法像您所要求的那样将两个字段匹配。您可以使用标准匹配条件获得“接近”的结果,但实际上让数组元素进行比较则需要更高级一点。
您正在寻找的“高级瑞士军刀”以
MongoDB聚合框架的形式呈现。它不仅可以“聚合”数据,还可以作为一般文档操作和评估的工具:
db.pop.aggregate([
{ "$match": {
"people.age": { "$lt": 30 },
"countries.population": { "$gt": 100000000 }
}},
{ "$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" ] }
]
}
}
}
}
}
}
}
}},
{ "$match": { "match": true }}
])
如果你想将它们“过滤”成匹配的结果,那么你可以稍微改变一下做法。我会将
$project
分阶段进行,但你也可以在一个阶段中完成:
db.pop.aggregate([
{ "$match": {
"people.age": { "$lt": 30 },
"countries.population": { "$gt": 100000000 }
}},
{ "$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
}},
{ "$match": { "people": { "$ne": false } }},
{ "$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]
]
}
}}
])
在第二种情况下,您将得到过滤掉不匹配数组元素的文档,如下所示:
{
"_id" : ObjectId("53c8f1645117367f5ff2036c"),
"people" : [
{
"name" : "Joseph",
"age" : 25,
"country" : "USA"
}
],
"countries" : [
{
"name" : "USA",
"population" : 300000000
}
]
}
非常强大的东西。
还可以在文档中查看聚合框架运算符和其他聚合示例。
您也可以使用mapReduce来做类似的事情,但通常更喜欢使用聚合框架,因为它是一种本地代码实现,而MongoDB mapReduce则依赖于JavaScript解释运行。