假设我的收藏中有以下文件:
{
"_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})
Or
db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})
返回匹配的文档(文档1),但总是使用形状中的ALL数组项:
{ "shapes":
[
{"shape": "square", "color": "blue"},
{"shape": "circle", "color": "red"}
]
}
但是,我想只获得包含color=red的数组的文档(文档1):
{ "shapes":
[
{"shape": "circle", "color": "red"}
]
}
我该怎么做呢?
MongoDB 2.2新的$elemMatch投影操作符提供了另一种方法来修改返回的文档,使其只包含第一个匹配的形状元素:
db.test.find(
{"shapes.color": "red"},
{_id: 0, shapes: {$elemMatch: {color: "red"}}});
返回:
{"shapes" : [{"shape": "circle", "color": "red"}]}
在2.2中,还可以使用$ projection操作符,其中投影对象字段名中的$表示查询中该字段的第一个匹配数组元素的索引。下面返回与上面相同的结果:
db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});
MongoDB 3.2更新
从3.2版本开始,您可以使用新的$filter聚合操作符在投影期间筛选数组,它的好处是包括所有匹配,而不仅仅是第一个匹配。
db.test.aggregate([
// Get just the docs that contain a shapes element where color is 'red'
{$match: {'shapes.color': 'red'}},
{$project: {
shapes: {$filter: {
input: '$shapes',
as: 'shape',
cond: {$eq: ['$$shape.color', 'red']}
}},
_id: 0
}}
])
结果:
[
{
"shapes" : [
{
"shape" : "circle",
"color" : "red"
}
]
}
]
使用聚合函数和$project获取文档中的特定对象字段
db.getCollection('geolocations').aggregate([ { $project : { geolocation : 1} } ])
结果:
{
"_id" : ObjectId("5e3ee15968879c0d5942464b"),
"geolocation" : [
{
"_id" : ObjectId("5e3ee3ee68879c0d5942465e"),
"latitude" : 12.9718313,
"longitude" : 77.593551,
"country" : "India",
"city" : "Chennai",
"zipcode" : "560001",
"streetName" : "Sidney Road",
"countryCode" : "in",
"ip" : "116.75.115.248",
"date" : ISODate("2020-02-08T16:38:06.584Z")
}
]
}
另一种有趣的方法是使用$编校,这是MongoDB 2.6的新聚合特性之一。如果您使用的是2.6,则不需要$unwind,如果您使用的是大型数组,$unwind可能会导致性能问题。
db.test.aggregate([
{ $match: {
shapes: { $elemMatch: {color: "red"} }
}},
{ $redact : {
$cond: {
if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
then: "$$DESCEND",
else: "$$PRUNE"
}
}}]);
$redact“根据存储在文档本身中的信息限制文档的内容”。所以它只会在文档内部运行。它基本上扫描你的文档从上到下,并检查它是否与你的if条件在$cond中匹配,如果有匹配,它将保留内容($$ descent)或删除($$PRUNE)。
在上面的例子中,第一个$match返回整个形状数组,$编校将其分解为预期的结果。
注意{$not:"$color"}是必要的,因为它也会扫描顶部的文档,如果$ react没有在顶部找到一个颜色字段,这将返回false,这可能会剥离整个文档,这是我们不想要的。