Mongoose 中的 Aggregate 介绍

Mongoose的 aggregate()函数 是您如何将 MongoDB 的Aggregation Framework 与 Mongoose 一起使用。 Mongoose的 aggregate()中工作的任何聚合查询都 MongoDB shell 应该在 Mongoose 中工作,无需任何更改。

什么是 Aggregation Framework ?

从语法上讲,Aggregation Framework 查询是一系列阶段。 阶段 是 MongoDB 如何转换进入阶段的任何文档的对象描述 第一阶段将文档馈送到第二阶段,依此类推,因此您可以使用阶段组合转换。 您传递给的阶段数组 aggregate() 函数称为聚合 管道 。

$match 阶段

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

await Character.create([
  { name: Jean-Luc Picard, age: 59, rank: Captain },
  { name: William Riker, age: 29, rank: Commander },
  { name: Deanna Troi, age: 28, rank: Lieutenant Commander },
  { name: Geordi La Forge, age: 29, rank: Lieutenant },
  { name: Worf, age: 24, rank: Lieutenant }
]);

const filter = { age: { $gte: 30 } };
let docs = await Character.aggregate([
  { $match: filter }
]);

docs.length; // 1
docs[0].name; // Jean-Luc Picard
docs[0].age // 59

// `$match` is similar to `find()`
docs = await Character.find(filter);
docs.length; // 1
docs[0].name; // Jean-Luc Picard
docs[0].age // 59

$group 阶段

聚合可以做的不仅仅是过滤文档。您还可以使用Aggregation Framework 来转换文档。 例如 $group 舞台表现得像 reduce() 功能 。 例如 $group stage 让您计算给定的字符数 age

let docs = await Character.aggregate([
  {
    $group: {
      // Each `_id` must be unique, so if there are multiple
      // documents with the same age, MongoDB will increment `count`.
      _id: $age,
      count: { $sum: 1 }
    }
  }
]);

docs.length; // 4
docs.sort((d1, d2) => d1._id - d2._id);
docs[0]; // { _id: 24, count: 1 }
docs[1]; // { _id: 28, count: 1 }
docs[2]; // { _id: 29, count: 2 }
docs[3]; // { _id: 59, count: 1 }

结合多个阶段

聚合管道的优势在于它的可组合性。 例如您可以结合前面的两个示例,仅按以下方式对字符进行分组 age 如果他们的 age< 30

let docs = await Character.aggregate([
  { $match: { age: { $lt: 30 } } },
  {
    $group: {
      _id: $age,
      count: { $sum: 1 }
    }
  }
]);

docs.length; // 3
docs.sort((d1, d2) => d1._id - d2._id);
docs[0]; // { _id: 24, count: 1 }
docs[1]; // { _id: 28, count: 1 }
docs[2]; // { _id: 29, count: 2 }

Mongoose Aggregate Class

Mongoose 的 aggregate() 函数返回一个 Mongoose 的实例 AggregateAggregate实例是 thenable ,因此您可以将它们与 await承诺链接

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

let docs = await Character.aggregate().
  match({ age: { $lt: 30 } }).
  group({ _id: $age, count: { $sum: 1 } });

docs.length; // 3
docs.sort((d1, d2) => d1._id - d2._id);
docs[0]; // { _id: 24, count: 1 }
docs[1]; // { _id: 28, count: 1 }
docs[2]; // { _id: 29, count: 2 }

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

const characterSchema = Schema({ name: String, age: Number });
characterSchema.pre(aggregate, function() {
  // Add a `$match` to the beginning of the pipeline
  this.pipeline().unshift({ $match: { age: { $lt: 30 } } });
});
const Character = mongoose.model(Character, characterSchema);

// The `pre(aggregate)` adds a `$match` to the pipeline.
let docs = await Character.aggregate().
  group({ _id: $age, count: { $sum: 1 } });

docs.length; // 3
docs.sort((d1, d2) => d1._id - d2._id);
docs[0]; // { _id: 24, count: 1 }
docs[1]; // { _id: 28, count: 1 }
docs[2]; // { _id: 29, count: 2 }
© 版权声明
THE END
喜欢就支持一下吧
点赞312 分享
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容