在子元素上使用 elemMatch 进行投影和过滤

Posted

技术标签:

【中文标题】在子元素上使用 elemMatch 进行投影和过滤【英文标题】:Project and filter using elemMatch on child elements 【发布时间】:2022-01-14 15:08:11 【问题描述】:

这是我收藏的内容:

[
  "_id": 
    "$oid": "61b253a89e51973f978b818d"
  ,
  "id": 1,
  "level1": [
    
      "name": "child11",
      "level2": [
        
          "name": "chil21"
        ,
        
          "name": "chilxx"
        
      ]
    ,
    
      "name": "child12",
      "level2": [
        
          "name": "chil23"
        ,
        
          "name": "chil24"
        
      ]
    
  ]
,
  "_id": 
    "$oid": "61b254b69e51973f978b818e"
  ,
  "id": 2,
  "level1": [
    
      "name": "child13",
      "level2": [
        
          "name": "chil25"
        ,
        
          "name": "chil26"
        
      ]
    ,
    
      "name": "child14",
      "level2": [
        
          "name": "chil27"
        ,
        
          "name": "chil28"
        ,
        
          "name": "chilxx"
        ,
        
          "name": "chil2a"
        
      ]
    
  ]
]

我现在想聚合这样的

聚合文档与集合中的原始文档具有相同的结构 level1 数组仅包含本身包含level2 元素和name = chilxx 的元素

因此,预期的聚合输出应该是:

[
  "_id": 
    "$oid": "61b253a89e51973f978b818d"
  ,
  "id": 1,
  "level1": [
    
      "name": "child11",
      "level2": [
        
          "name": "chil21"
        ,
        
          "name": "chilxx"
        
      ]
    
  ]
,
  "_id": 
    "$oid": "61b254b69e51973f978b818e"
  ,
  "id": 2,
  "level1": [
    
      "name": "child14",
      "level2": [
        
          "name": "chil27"
        ,
        
          "name": "chil28"
        ,
        
          "name": "chilxx"
        ,
        
          "name": "chil2a"
        
      ]
    
  ]
]

这是我的(不工作的)聚合方法:

[
  
    '$match': 
  , 
    '$project': 
      '_id': 1, 
      'id': 1, 
      'level1': 
        '$filter': 
          'input': '$level1', 
          'as': 'l1', 
          'cond': 
            '$$l1.level2': 
              '$elemMatch': 
                'name': 'chilxx'
              
            
          
        
      
    
  
]

但是,这会导致错误:

Invalid $project :: caused by :: Unrecognized expression '$$l1.level2'

提前谢谢你。

【问题讨论】:

【参考方案1】: $match $set
db.collection.aggregate([
  
    "$match": 
      "level1.level2.name": "chilxx"
    
  ,
  
    "$set": 
      "level1": 
        "$filter": 
          "input": "$level1",
          "as": "first",
          "cond": 
            $ne: [
              
                "$filter": 
                  "input": "$$first.level2",
                  "as": "second",
                  "cond": 
                    $eq: [
                      "$$second.name",
                      "chilxx"
                    ]
                  
                
              ,
              []
            ]
          
        
      
    
  
])

mongoplayground

【讨论】:

太棒了。我从中学到了两件事。 $set 可以更容易地保持原始结构,并且可以使用 $ne 排除空列表。我将您的答案应用于我的(更复杂的)结构,它按预期工作。

以上是关于在子元素上使用 elemMatch 进行投影和过滤的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 $elemMatch 查找和过滤并更新数组的所有元素该元素在猫鼬中有一个特殊的日期?

MongoDB:$ elemMatch和$ and和在数组内查找对象之间有什么区别?

MongoDB Compass:对数组对象的过滤查询不起作用

怎样清理投影机过滤网灰尘?

如何进行 bigquery 传输:数据集投影

mongodb 中的Multikey Index Bounds解释$elemMatch