【问题标题】: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 会忽略 $ 之后的路径部分

有办法吗?

【问题讨论】:

    标签: mongodb projection embedded-documents positional-operator


    【解决方案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 中的解决方案,但使用聚合框架 ...
    猜你喜欢
    • 1970-01-01
    • 2023-03-04
    • 2023-03-31
    • 2021-05-06
    • 2016-03-26
    • 1970-01-01
    • 1970-01-01
    • 2015-05-23
    相关资源
    最近更新 更多