【问题标题】:multiple conditions in $match in mongodbmongodb中$match中的多个条件
【发布时间】:2020-08-02 22:43:04
【问题描述】:

我有一个集合 AccountSupport。我有一系列支持属性。我想过滤父属性和数组属性的记录

db = {
  "AccountSupport": [
    {
    "_id" : ObjectId("5e9c6170b38c373530c5b00a"),
    "accountName" : "domestic",
    "supports" : [ 
        {
            "subject" : "Traverse",
            "desc" : "Travers support consolidation",
        }, 
        {
            "subject" : "Non Traverse",
            "desc" : "Non Travers support consolidation",
        },
        {
            "subject" : "Domestic Traverse",
            "desc" : "Domestic Travers support consolidation",
        }       
    ],

  }

我想过滤 accountName 和 support.subject。

以下是我的查询

db.AccountSupport.aggregate([
  {
    "$match": {
      "$and": [
        {
          "supports.subject": "Traverse"
        },
        {
          "accountName": "domestic"
        }
      ]
    }
  },
  {
    "$unwind": "$supports"
  },
  {
    "$project": {
      "SupportName": "$supports.subject",
      "desc": "$supports.desc"
    }
  }
])

上面的查询返回给我一个特定 accountName 的所有支持,而我只想要匹配主题的单个对象。以上是最简单的方法吗?

MongoPlayGround

MongoPlayGround for my query

【问题讨论】:

  • 关于您对 Lean() 的评论,您是否使用了诸如 Mongoose 之类的 ORM?
  • @james 是的,我正在使用猫鼬
  • 所以在你的 js 代码中,你能不能只获取第一个元素 [0] 来删除方括号,然后获取 "subject" 的第一个元素来返回 { accountName: 'domestic' { " SupportName": "Traverse", "desc": "Travers 支持合并" } }
  • 是的,我只是这样做了,但我在答案中发布的查询也是如此。

标签: mongodb mongoose aggregation-framework match aggregate


【解决方案1】:

进行了一些实验,但试试这个:

db.AccountSupport.aggregate([
  {
    $match: {
      "accountName": "domestic",
      "supports.subject": "Traverse"
    }
  },
  {
    $project: {
      accountName: "$accountName",
      subject: {
        $filter: {
          input: "$supports",
          as: "supports",
          cond: {
            $eq: [
              "$$supports.subject",
              "Traverse"
            ]
          }
        }
      },
      _id: 0
    }
  }
])

返回:

[
  {
    "accountName": "domestic",
    "subject": [
      {
        "desc": "Travers support consolidation",
        "subject": "Traverse"
      }
    ]
  }
]

【讨论】:

    【解决方案2】:

    一种选择是在聚合查询中添加另一个$match 步骤。由于 $unwind 将您的文档分成 3 个文档,因此您可以匹配您有兴趣返回的单个文档。 james 的 $filter 解决方案看起来值得研究,对您来说可能是更简单的方法。

    查询:

    db.AccountSupport.aggregate([
      {
        "$match": {
          "$and": [
            {
              "supports.subject": "Traverse"
            },
            {
              "accountName": "domestic"
            }
          ]
        }
      },
      {
        "$unwind": "$supports"
      },
      {
        "$match": {
          "supports.subject": "Traverse"
        }
      },
      {
        "$project": {
          "SupportName": "$supports.subject",
          "desc": "$supports.desc"
        }
      }
    ])
    

    结果:

    [
      {
        "SupportName": "Traverse",
        "_id": ObjectId("5e9c6170b38c373530c5b00a"),
        "desc": "Travers support consolidation"
      }
    ]
    

    MongoPlayground

    【讨论】:

    • 一个好答案!您可以在 $project 字段中添加 _id: 0 作为最终参数,以从响应中删除 ID - 然后我认为您的答案现在胜过我的 :) mongoplayground.net/p/N_AQwn98TPO
    • @james - 我把 _id 留在了那里,因为 OP 没有提到任何关于包含或排除它的内容。不确定哪个更干净/更好 - 在 $project 中使用 $filter 或执行 $unwind 和 $match - 很高兴有多个选项可供选择。
    • 这是真的!不知道为什么我脑子里有这个。但是是的,多种解决方案总是好的。
    • 应该做任何可以避免$unwind的事情。 james 的回答是这个用例的最佳实践:如果数组中至少出现 1 个匹配项,则使用数组中项目的点路径来产生 T 或 F,然后 $filter 只保留目标项目。
    • @james 我也在尝试在响应中获取 accountName,如下所示 { accountName: 'domestic' { "SupportName": "Traverse", "desc": "Travers supportsolidation" }我也试图将响应作为普通对象而不是 mongooseCoreArray 我尝试使用 LEAN() 但它不起作用。
    【解决方案3】:

    以下是获取我需要的结果的查询,但不确定这是否是最佳做法,因为发布的其他答案也适用于上述要求

    db.AccountSupport.find({'accountName': 'domestic' },
                          { 
                             'supports': 
                                    { 
                                      '$elemMatch': { 'subject': 'Traverse'}
                                    }
                           })
    

    【讨论】:

      猜你喜欢
      • 2019-04-20
      • 2019-10-09
      • 1970-01-01
      • 2019-04-04
      • 2018-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多