从与数组上的查询条件匹配的第一个元素中投影特定字段

Posted

技术标签:

【中文标题】从与数组上的查询条件匹配的第一个元素中投影特定字段【英文标题】:Project a specific field from the first element that matches the query condition on the array 【发布时间】:2021-05-10 21:30:20 【问题描述】:

我有一个families 收藏。其中的文档有一个users 数组。鉴于这份家庭文件:


    "id" : "1",
    "users" : [ 
        
            "id" : "2",
            "identities" : [ 
                
                    "type" : "email",
                    "email" : "foo"
                , 
                
                    "type" : "email",
                    "email" : "bar"
                
            ]
        , 
        
            "id" : "3",
            "identities" : [ 
                
                    "type" : "email",
                    "email" : "baz"
                , 
                
                    "type" : "email",
                    "email" : "qux"
                
            ]
        
    ]

我想投影identities 数组元素的type 字段,但仅限于我查询的特定用户。位置运算符获得正确的用户:

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 的用户,但返回所有字段的身份数组元素)。 想试试这个:

db.families.findOne(
     'users.id': '2' ,
     'users.$.identities.type': 1  
  )

但是自从per the docs之后就不行了:

MongoDB 会忽略 $ 之后的路径部分

有办法吗?

【问题讨论】:

【参考方案1】:

您只需要使用 $ 运算符来投影一个字段。

查询:

db.collection.find(
  "users.id": "2"
,

  "users.identities.type.$": 1
);

结果:

[
  
    "_id": "1",
    "users": [
      
        "identities": [
          
            "type": "email"
          ,
          
            "type": "email"
          
        ]
      
    ]
  
]

【讨论】:

谢谢,但在 mongodb 4.2.1 上对此进行了测试,它返回了正确的用户,但所有字段都在 identities 数组元素中。 您是否尝试过指定排除“电子邮件”字段? "users.identities.type.$": 1, "users.identities.email.$": 0 【参考方案2】:

这将仅投影所选 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","users":id:1,"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 阶段,您只投影您需要的字段

【讨论】:

谢谢,但在 mongodb 4.2.1 中进行了测试,并收到此投影错误:">1 field in obj: id: 1.0, identities: type.$: 1.0 " 在 4.4.3 中运行良好... :) ,也许是时候升级了... 添加到我的答案也是 4.2.12 中的解决方案,但使用聚合框架 ...

以上是关于从与数组上的查询条件匹配的第一个元素中投影特定字段的主要内容,如果未能解决你的问题,请参考以下文章

在 mongodb 中投影集合类型数组的大小

SQL 查询:是不是可以在单个查询中投影四个结果?

如何从对象数组中投影所有嵌套文档?

在 OpenGL 中投影纹理

OpenGL中投影矩阵基础知识

ARCGIS中投影转换后为啥只是投影信息变了,图内坐标并没有变化?