假设您的集合中包含以下文档:
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"shapes":[
{
"shape":"square",
"color":"blue"
},
{
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"shapes":[
{
"shape":"square",
"color":"black"
},
{
"shape":"circle",
"color":"green"
}
]
}
查询:
db.test.find({"shapes.color": "red"}, {"shapes.color": 1})
要么
db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})
返回匹配的文档(文档1),但始终包含 shapes
中的所有数组项:
{ "shapes":
[
{"shape": "square", "color": "blue"},
{"shape": "circle", "color": "red"}
]
}
但是,我想仅使用包含 color=red
的数组获取文档(文档1):
{ "shapes":
[
{"shape": "circle", "color": "red"}
]
}
我怎样才能做到这一点?
11 回答
感谢JohnnyHK .
在这里,我只想添加一些更复杂的用法 .
更好的是你可以使用
$slice
查询匹配数组元素是否有助于返回数组中的重要对象 .当您知道元素的索引时,
$slice
会很有用,但有时您需要符合条件的数组元素 . 您可以使用$
运算符返回匹配元素 .产出
MongoDB 2.2中的新Aggregation Framework提供了Map / Reduce的替代方案 . $unwind运算符可用于将
shapes
数组分隔为可匹配的文档流:结果是:
字段选择器参数仅限于完整属性 . 它不能用于选择数组的一部分,只能用于整个数组 . 我尝试使用$ positional operator,但这不起作用 .
最简单的方法是过滤形状 in the client .
如果你真的需要直接从MongoDB输出正确的输出,你可以 use a map-reduce 过滤形状 .
与$ project一起,更合适的是其他明智的匹配元素将与文档中的其他元素一起使用 .
您只需要运行查询
此查询的输出是
如你所料,它将从匹配颜色的数组中提供确切的字段:'red' .
MongoDB 2.2的新$elemMatch投影运算符提供了另一种方法来更改返回的文档,使其仅包含 first 匹配的
shapes
元素:返回:
在2.2中,您也可以使用$ projection operator执行此操作,其中投影对象字段名称中的
$
表示字段中查询的第一个匹配数组元素的索引 . 以下返回与上面相同的结果:MongoDB 3.2 Update
从3.2版本开始,您可以使用新的$filter聚合运算符在投影期间过滤数组,这样可以包含所有匹配,而不仅仅是第一个匹配 .
结果:
在mongodb中查找的语法是
和你写的第二个查询,即
在这里你在查询部分使用了
$elemMatch
运算符,而如果你在投影部分使用这个运算符,那么你将得到所需的结果 . 您可以将查询写下来这将为您提供所需的结果 .
另一种有意思的方法是使用$redact,这是 MongoDB 2.6 的新聚合功能之一 . 如果您使用的是2.6,则不需要$ unwind,如果您有大型数组,可能会导致性能问题 .
$redact
"restricts the contents of the documents based on information stored in the documents themselves" . 所以它只会在文档内部运行 . 它基本上扫描你的文档顶部到底部,并检查它是否与$cond
中的if
条件匹配,如果匹配,它将保留内容($$DESCEND
)或删除($$PRUNE
) .在上面的示例中,首先
$match
返回整个shapes
数组,$ redact将其删除到预期结果 .请注意
{$not:"$color"}
是必要的,因为它也会扫描顶层文档,如果$redact
在顶层找不到color
字段,则会返回false
,这可能会删除我们不想要的整个文档 .