在MongoDB中创建值和出现次数的聚合列表

xnifntxz  于 2023-11-17  发布在  Go
关注(0)|答案(1)|浏览(203)

鉴于以下文件:

[
  {
    _id: "N0001",
    name: "Bruce Lee",
    skills: ["karate", "jiu jitsu"],
  },
  {
    _id: "N0002",
    name: "Bruce Dee",
    skills: ["karate", "tae kwon do"],
  },
  {
    _id: "N0003",
    name: "Bruce See",
    skills: ["aikido", "jiu jitsu"],
  },
  {
    _id: "N0004",
    name: "Deuce Lee",
    skills: ["karate", "judo"],
  },
]

字符串
我想得到以下信息:

{
  karate: 3,
  jiu jitsu: 2,
  tae kwon do: 1,
  judo: 1,
  aikido: 1,
}


现在,我可以用下面这样的脚本来获得上面的内容:

const uniqueSkills = db.fighters.distinct('skills');
console.log(
  Object.fromEntries(
    uniqueSkills.map(
      async m => [m, await db.fighters.find({ skills: m }).length]
    )
  )
)


但是我真的很想把这整个事情保持在聚合框架内,而不是使用节点运行时来重复进行这个查询,我完全不知道如何做到这一点。注意,技能集是有限的,但未知的,所以我不能从已知的技能列表开始,然后把它们硬编码到查询本身中。

vlurs2pr

vlurs2pr1#

这样做的一种方法如下:

db.collection.aggregate([
  {
    $unwind: "$skills"
  },
  {
    $group: {
      _id: "$skills",
      count: {
        $sum: 1
      }
    }
  },
  {
    $group: {
      _id: null,
      skills: {
        "$addToSet": {
          k: "$_id",
          v: "$count"
        }
      }
    }
  },
  {
    "$replaceRoot": {
      "newRoot": {
        "$arrayToObject": "$skills"
      }
    }
  }
])

字符串
使用示例输入的输出为:

{
  "aikido": 1,
  "jiu jitsu": 2,
  "judo": 1,
  "karate": 3,
  "tae kwon do": 1
}


我们在这里:

  1. $unwind执行skills数组以获取各个条目。
  2. $group将这些技能组合在一起以获得计数
  3. $group将这些组组合在一起,以将所有条目放入单个文档中
    1.使用$replaceRoot重塑文档。
    第三步和第四步是为了利用the $arrayToObject operator而设计的。
    看看它在this playground example中是如何工作的。
    我很确定还有其他方法可以做到这一点。同样需要注意的是,随着数据集的增长,这种操作将是资源密集型的,但这只是像这样的分析操作必须针对该模式运行的自然结果。

相关问题