【问题标题】:Project specific fields of embedded documents嵌入文档的项目特定字段
【发布时间】:2018-04-06 03:12:30
【问题描述】:

我试图只获取特定嵌入文档的一个字段。

嵌入的文档应该基于两个条件和 然后只返回该嵌入文档的一个字段。

db.usertest.insertMany(
    [{
    "username" : "userA",
    "objects" : [
        {
        "type" : "fruit",
        "origin" : "ABC",
        "name" : "banana",
        },
        {
        "type" : "fruit",
        "origin" : "XYZ",
        "name" : "pineapple",
        },

        {
        "type" : "vegetable",
        "origin" : "XYZ",
        "name" : "carrot"
        }
    ]
    },
     {
     "username" : "userB",
     "objects" : []
     }
]
)

我想查找“用户名”字段和“名称”字段 嵌入文档。

首先我想到了 $elemMatch,但我被困在了 $project 部分并且 它只返回所有嵌入文档的字段“名称” $elemMatch 是真的。

db.usertest.aggregate(
    [{$match:{"objects": {"$elemMatch":{
         "type": "fruit",
         "origin": "XYZ"}}}},
     {$project: {
      "username":1,
      "objects.name":1
      }}]
).pretty()

然后我想到了使用 $filter,但它显然只是返回 整个嵌入文档,而不仅仅是“名称”字段。

db.usertest.aggregate(
    [{$project: {
      "username":1,
      "name":{
          $filter: {
             input: "$objects",
             cond: { $and: [
                     { $eq: [ "$$this.type", "fruit" ] },
                  { $eq: [ "$$this.origin", "XYZ" ] }
                 ]}
          }}
      }}]
).pretty()

有什么想法吗?

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    您可以按以下顺序组合多个聚合运算符:

    $filter -> $map(仅获取 name 属性)-> $arrayElemAt(获取第一个元素)

    db.usertest.aggregate(
      [{$project: {
        "username":1,
        "name": {
          $arrayElemAt: [
            {
              $map: {
                input: {
                  $filter: {
                     input: "$objects",
                     cond: { $and: [
                             { $eq: [ "$$this.type", "fruit" ] },
                          { $eq: [ "$$this.origin", "XYZ" ] }
                         ]}
                  }},
                  as: "item",
                  in: "$$item.name"
              }
            },0
          ]
        }
        }}]
    ).pretty()
    

    【讨论】:

    • 完美!我错过了地图和过滤器的组合。谢谢!很高兴您的解决方案甚至允许注释掉 arrayElemAt,然后在给定条件的情况下,我有一个包含所有名称的数组。
    【解决方案2】:

    no $elemMatch operator$project 阶段。因此,要使用模仿类似的功能,您可以使用索引为 0 的 $arrayElemAt$let 创建 $filter,以将中间文档保存在变量中并输出名称。

    保留$match 阶段,以便您只查看至少有一个匹配对象的文档。

    类似

    db.usertest.aggregate(
    [{"$match":{"objects":{"$elemMatch":{"type":"fruit","origin":"XYZ"}}}},
    {"$project":{
      "name":{"$let":{
        "vars":{"object":{
          "$arrayElemAt":[
            {"$filter":{
              "input":"$objects",
              "as":"o",
              "cond":{
                "$and":[
                  {"$eq":["$$o.type","fruit"]},
                  {"$eq":["$$o.origin","XYZ"]}
                ]
              }
            }},
            0
          ]
        }},
        "in":"$$object.name"
      }}
    }}])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多