首页 > 解决方案 > 如果在数组中找不到匹配项,则返回第一个元素

问题描述

我有以下文件:

{
    _id: 123,
    state: "AZ",
    products: [
        {
            product_id: 1,
            desc: "P1"
        },
        {
            product_id: 2,
            desc: "P2"
        }   
    ]
}

我需要编写一个查询以从 products 数组中返回一个元素,其中 state 为“AZ”且 product_id 为 2。如果找不到匹配的 product_id,则返回 products 数组中的第一个(或任何)元素。

例如:如果 product_id 为 2(找到匹配项),则结果应为:

products: [
    {
        product_id: 2,
        desc: "P2"
    }   
]

如果 product_id 为 3(未找到),则结果应为:

products: [
    {
        product_id: 1,
        desc: "P1"
    }   
]

找到匹配项时,我能够满足一个条件,但不确定如何满足同一查询中的第二个条件:

db.getCollection('test').find({"state": "AZ"}, {_id: 0, state: 0, products: { "$elemMatch": {"product_id": "2"}}})

我也尝试使用聚合管道,但找不到有效的解决方案。

注意:这与以下问题不同,因为如果找不到匹配项,我需要返回默认元素: Retrieve only the queried element in an object array in MongoDB collection

标签: mongodbaggregation-framework

解决方案


您可以尝试以下聚合

基本上你需要数组并检查它是否不包含任何元素或等于然后你必须$filter使用数组的第一个元素。products$cond[]$sliceproducts

db.collection.aggregate([
  { "$addFields": {
    "products": {
      "$cond": [
        {
          "$eq": [
            { "$filter": {
              "input": "$products",
              "cond": { "$eq": ["$$this.product_id", 2] }
            }},
            []
          ]
        },
        { "$slice": ["$products", 1] },
        { "$filter": {
          "input": "$products",
          "cond": { "$eq": ["$$this.product_id", 2] }
        }}
      ]
    }
  }}
])

甚至使用$let聚合

db.collection.aggregate([
  { "$addFields": {
    "products": {
      "$let": {
        "vars": {
          "filt": {
            "$filter": {
              "input": "$products",
              "cond": { "$eq": ["$$this.product_id", 2] }
            }
          }
        },
        "in": {
          "$cond": [
            { "$eq": ["$$filt", []] },
            { "$slice": ["$products", 1] },
            "$$filt"
          ]
        }
      }
    }
  }}
])

推荐阅读