这是单个文档:
{
_id: "...",
firstName: "john",
lastName:"Doe",
cars: [
{
"_id": "...",
"carName": "BMW",
"carModel": "330",
"carColor": "silver"
},
{
"_id": "...",
"carName": "Lexus",
"carModel": "IS300",
"carColor": "white"
},
{
"_id": "...",
"carName": "LADA",
"carModel": "2106",
"carColor": "blue"
}
]
}
我只想选约翰的宝马的“汽车颜色”。
像这样的:
db.persons.findOne(
{ "firstName": "John", "cars.carName": "BMW" },
{ "_id": 0, "cars.$.carColor": 1 }
);
但此查询返回完整对象,如下所示:
{
cars: [
{
"_id": "...",
"carName": "BMW",
"carModel": "330",
"carColor": "silver"
}
}
我已经尝试了不同的查询没有。$。符号:
db.persons.findOne(
{ "firstName": "John", "cars.carName": "BMW" },
{ "_id": 0, "cars.carColor": 1 }
);
此版本只返回“carcolor”属性,但不过滤“carname”。
这样地:
{
cars: [
{
"carColor": "silver"
},
{
"carColor": "white"
},
{
"carColor": "blue"
}
]
}
有什么想法吗?
最佳答案
为什么不起作用?
{“firstname”:“john”,“cars.carname”:“bmw”}
意思是“在哪里名字是约翰,在哪里至少有一个条目在汽车数组中,卡纳姆是“宝马”。但它返回完整的文档,而不过滤数组。
{“{id”:0,“cars.carcolor”:1}
不投射id,而是投射car数组中所有条目的carcolor。
解决方案
事实上,使用find和projection方法并不能完全达到您想要的效果。最好是这样添加$ projection operator:
db.collection.find({
firstName: "john",
"cars.carName": "BMW"
},
{
_id: 0,
"cars.$": 1
})
**RESULT**
[
{
"cars": [
{
"_id": "...",
"carColor": "silver",
"carModel": "330",
"carName": "BMW"
}
]
}
]
但这种方法有缺点:
你得到了整个数组条目,而不仅仅是你想要/需要的颜色
它只返回第一个匹配的条目:如果john有两辆bmw,则只返回一辆。
更好的解决方案
幸运的是,mongodb提供了另一种方法来实现这一点,它使用聚合框架和$filter操作符:
db.collection.aggregate([
{
$match: {
firstName: "john"
}
},
{
$project: {
cars: {
$filter: {
input: "$cars",
as: "cars",
cond: {
$eq: [
"$$cars.carName",
"BMW"
]
}
}
}
}
},
{
$project: {
_id: 0,
"colors": "$cars.carColor"
}
}
])
You can try it here.
编辑:其他解决方案
您也可以尝试使用“展开/分组”阶段:
db.collection.aggregate([
{
$match: {
firstName: "john"
}
},
{
$unwind: "$cars"
},
{
$match: {
"cars.carName": "BMW"
}
},
{
$group: {
"_id": null,
colors: {
$push: "$cars.carColor"
}
}
}
])