MongoDB:确定是否有任何对象具有特定子数组值的特定计数

MongoDB: determining if there are any objects with a specific count for a particular sub-array value

基本上,我有:

例如:

// a band
{
  _id: 1,
  players: [
    { 
      name: "George",
      roles: [ "GUITAR" ]
    },
    { 
      name: "John",
      roles: [ "SINGER", "GUITAR" ]
    },
    { 
      name: "Paul",
      roles: [ "SINGER", "BASS GUITAR" ]
    },
    { 
      name: "Ringo",
      roles: [ "DRUMS" ]
    },
  ]
}

我需要确定是否有任何乐队包含多个成员SINGER角色。

一些简单的选项:

db.collection.aggregate([
 {
   $unwind: "$players"
  },
 {
   $unwind: "$players.roles"
 },
 {
   $match: {
     "players.roles": "SINGER"
  }
  },
   {
   $group: {
    _id: "$_id",
    cnt: {
    $sum: 1
    }
   }
  },
  {
    $match: {
     cnt: {
      $gt: 1
      }
    }
  }
 ])

解释:

  1. 展开第一个数组
  2. 展开第二个数组
  3. 仅过滤角色 SINGER
  4. 按乐队 _id 分组并计算 SINGER 角色。
  5. 只过滤超过 1 个 SINGER
  6. 的乐队

playground

$unwind / $group 解决方案的替代方案是 $filter:

db.collection.aggregate([
  {
    $match: {
      "players.roles": "GUITAR"
    }
  },
  {
    "$set": {
      "member_cnt": {
        $size: {
          $filter: {
            input: "$players",
            cond: {
              $in: [
                "GUITAR",
                "$$this.roles"
              ]
            }
          }
        }
      }
    }
  },
  {
    $match: {
      "member_cnt": {
        $gt: 1
      }
    }
  },
  {
    "$project": {
      member_cnt: 0
    }
  }
])

它应该会快一点,因为它没有阻塞 $group stage。

这个查询似乎给了我我需要的东西:

db.bands.aggregate([
  {
    $addFields: {
      players: {
        $ifNull: [
          "$players",
          []
        ]
      }
    }
  },
  {
    "$match": {
      "$expr": {
        "$gt": [
          {
            "$size": {
              "$filter": {
                "input": "$players",
                "as": "player",
                "cond": {
                  "$in": [
                    "SINGER",
                    "$$player.roles"
                  ]
                }
              }
            }
          },
          1
        ]
      }
    }
  }
])