问题描述
我有一个 families
集合。其中的文档有一个 users
数组。鉴于此家庭文件:
{
"id" : "1","users" : [
{
"id" : "2","identities" : [
{
"type" : "email","email" : "foo"
},{
"type" : "email","email" : "bar"
}
]
},{
"id" : "3","email" : "baz"
},"email" : "qux"
}
]
}
]
}
我想投影 type
数组元素的 identities
字段,但只能来自我查询的特定用户。位置运算符获得正确的用户:
db.families.findOne(
{ 'users.id': '2' },{ 'users.$': 1 }
)
我可以指定我感兴趣的字段:
db.families.findOne(
{ 'users.id': '2' },{ 'users.identities.type': 1 }
)
但是当两者结合时,只考虑位置运算符:
db.families.findOne(
{ 'users.id': '2' },{ 'users.$': 1,'users.identities.type': 1 }
)
(返回 id 为 2 的用户,但返回包含所有字段的 identities 数组元素)。 想试试这个:
db.families.findOne(
{ 'users.id': '2' },{ 'users.$.identities.type': 1 }
)
但它不好,因为per the docs:
MongoDB 忽略 $
后面的路径部分有办法吗?
解决方法
您只需使用 $ 运算符来投影字段。
查询:
db.collection.find({
"users.id": "2"
},{
"users.identities.type.$": 1
});
结果:
[
{
"_id": "1","users": [
{
"identities": [
{
"type": "email"
},{
"type": "email"
}
]
}
]
}
]
,
这将仅投影所选 users.id 的类型和 users.id:
db.families.findOne({"users.id":"2"},{"users":{id:1,"identities.type.$":1}})
{
"_id" : ObjectId("601f1974cf95940e8e0c814e"),"users" : [
{
"id" : "2","identities" : [
{
"type" : "email"
},{
"type" : "email"
}
]
}
]
}
(在 mongod 4.4.3 中测试) 也可以这样重写(也是 4.4.3 ):
db.families.findOne({"users.id":"2"},"identities":{"type.$":1}}})
在 mongod 4.2.12 中可以通过以下聚合实现相同的结果:
db.families.aggregate([
{$project:{users:{$filter:{input:"$users",as:"us",cond:{$eq:["$$us.id","2"]}}}}},{$project:{"users.identities.type":1,"users.id":1 }}
])
聚合解释:
- 在第一个 $project 阶段,您过滤 users.id:2 的数组元素
- 在第二个 $project 阶段,您只投影您需要的字段