Mongoose aggregate

作者: lio_zero | 来源:发表于2022-06-12 14:54 被阅读0次

    本文已整理到 Github,地址 👉 blog

    如果我的内容帮助到了您,欢迎点个 Star 🎉🎉🎉 鼓励鼓励 :) ~~

    我希望我的内容可以帮助你。现在我专注于前端领域,但我也将分享我在有限的时间内看到和感受到的东西。


    Mongoose aggregate

    Mongoose 的 aggregate() 方法是如何将 MongoDB 的聚合框架与 Mongoose 一起使用的。Mongoose aggregate() 是一个小的包装器,因此任何在 MongoDB shell(mongo中工作的任何聚合查询都应该在 Mongoose 中工作,而不做任何更改。

    什么是聚合框架?

    从语法上讲,聚合框架查询是一个阶段数组。阶段是 MongoDB 应该如何转换进入该阶段的任何文档的对象描述。第一阶段将文档馈送到第二阶段,依此类推,这样您就可以使用阶段组合转换。传递给 aggregate() 方法的阶段数组称为聚合管道。

    $match 阶段

    $match 阶段过滤掉与给定 filter 参数不匹配的文档 ,类似于 Mongoose find() 方法的过滤器。

    await User.create([
      { name: 'O.O', age: 18 },
      { name: 'D.O', age: 19 },
      { name: 'K.O', age: 31 },
      { name: 'O.K', age: 19 },
      { name: 'LAY', age: 28 }
    ])
    
    const filter = {
      age: {
        $gte: 30
      }
    }
    
    let docs = await User.aggregate([{ $match: filter }])
    
    console.log(docs.length) // 1
    console.log(docs[0].name) // K.O
    console.log(docs[0].age) // 31
    
    // $match 类似于 find()
    docs = await User.find(filter)
    console.log(docs.length) // 1
    console.log(docs[0].name) // 'K.O'
    console.log(docs[0].age) // 31
    

    $group 阶段

    聚合可以做的不仅仅是过滤文档。您还可以使用聚合框架来转换文档。例如,$group 阶段的行为类似于 reduce() 方法。例如,$group 阶段允许您计算给定 age 的用户数量。

    let docs = await User.aggregate([
      {
        $group: {
          // 每个 _id 都必须是唯一的,因此如果有多个文档具有相同的期限,MongoDB 将增加 count。
          _id: '$age',
          count: {
            $sum: 1
          }
        }
      }
    ])
    
    console.log(docs.length) // 4
    docs.sort((d1, d2) => d1._id - d2._id)
    console.log(docs[0]) // { _id: 18, count: 1 }
    console.log(docs[1]) // { _id: 19, count: 2 }
    console.log(docs[2]) // { _id: 28, count: 1 }
    console.log(docs[3]) // { _id: 31, count: 1 }
    

    结合多个阶段

    聚合管道的优势在于其可组合性。例如,结合前两个例子,仅按 age 对用户进行分组,条件为 age < 30

    let docs = await User.aggregate([
      {
        $match: {
          age: {
            $lt: 30
          }
        }
      },
      {
        $group: {
          _id: '$age',
          count: {
            $sum: 1
          }
        }
      }
    ])
    
    console.log(docs.length) // 3
    docs.sort((d1, d2) => d1._id - d2._id)
    console.log(docs[0]) // { _id: 18, count: 1 }
    console.log(docs[1]) // { _id: 19, count: 2 }
    console.log(docs[2]) // { _id: 28, count: 1 }
    

    Mongoose Aggregate

    Mongoose 的 aggregate() 方法返回 Mongoose Aggregate的实例 。Aggregate 聚合实例是可聚合的,因此您可以将它们与 await 和 Promise 链一起使用。

    Aggregate 类还支持用于构建聚合管道的链接接口。例如,下面的代码显示了另一种用于构建聚合管道的语法,该聚合管道后跟 $match$group

    let docs = await User.aggregate()
      .match({ age: { $lt: 30 } })
      .group({ _id: '$age', count: { $sum: 1 } })
    
    console.log(docs.length) // 3
    docs.sort((d1, d2) => d1._id - d2._id)
    console.log(docs[0]) // { _id: 18, count: 1 }
    console.log(docs[1]) // { _id: 19, count: 2 }
    console.log(docs[2]) // { _id: 28, count: 1 }
    

    Mongoose 中间件也支持 pre('aggregate')post('aggregate') 钩子。您可以使用聚合中间件来转换聚合管道。

    const userSchema = Schema({ name: String, age: Number })
    userSchema.pre('aggregate', function () {
      // 将 $match 添加到管道的开头
      this.pipeline().unshift({ $match: { age: { $lt: 30 } } })
    })
    const User = mongoose.model('User', userSchema)
    
    // pre('aggregate') 向管道中添加一个 $match。
    let docs = await User.aggregate().group({
      _id: '$age',
      count: { $sum: 1 }
    })
    
    console.log(docs.length) // 3
    docs.sort((d1, d2) => d1._id - d2._id)
    console.log(docs[0]) // { _id: 18, count: 1 }
    console.log(docs[1]) // { _id: 19, count: 2 }
    console.log(docs[2]) // { _id: 28, count: 1 }
    

    相关文章

      网友评论

        本文标题:Mongoose aggregate

        本文链接:https://www.haomeiwen.com/subject/odbgmrtx.html