Mongoose的 aggregate()
函数 是您如何将 MongoDB 的Aggregation Framework 与 Mongoose 一起使用。 Mongoose的 aggregate()
中工作的任何聚合查询都 MongoDB shell 应该在 Mongoose 中工作,无需任何更改。
什么是 Aggregation Framework ?
从语法上讲,Aggregation Framework 查询是一系列阶段。 阶段 是 MongoDB 如何转换进入阶段的任何文档的对象描述 第一阶段将文档馈送到第二阶段,依此类推,因此您可以使用阶段组合转换。 您传递给的阶段数组 aggregate()
函数称为聚合 管道 。
$match
阶段
$match
阶段过滤掉与给定不匹配的文档 filter
参数,类似于 Mongoose 的 find()
功能 。
<code class="language-javascript">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; // 1docs[0].name; // Jean-Luc Picarddocs[0].age // 59// `$match` is similar to `find()`docs = await Character.find(filter);docs.length; // 1docs[0].name; // Jean-Luc Picarddocs[0].age // 59</code><code class="language-javascript">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</code>
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; // 1docs[0].name; // Jean-Luc Picarddocs[0].age // 59// `$match` is similar to `find()`docs = await Character.find(filter);docs.length; // 1docs[0].name; // Jean-Luc Picarddocs[0].age // 59await 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 // 59await 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
。
<code class="language-javascript">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; // 4docs.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 }</code><code class="language-javascript">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 }</code>
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; // 4docs.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 }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 }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
。
<code class="language-javascript">let docs = await Character.aggregate([{ $match: { age: { $lt: 30 } } },{$group: {_id: $age,count: { $sum: 1 }}}]);docs.length; // 3docs.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 }</code><code class="language-javascript">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 }</code>
let docs = await Character.aggregate([{ $match: { age: { $lt: 30 } } },{$group: {_id: $age,count: { $sum: 1 }}}]);docs.length; // 3docs.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 }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 }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 的实例 Aggregate
类 。Aggregate
实例是 thenable ,因此您可以将它们与 await
和 承诺链接。
Aggregate
类还支持用于构建聚合管道的链接接口。 例如,下面的代码显示了构建聚合管道的另一种语法 $match
其次是 $group
。
<code class="language-javascript">let docs = await Character.aggregate().match({ age: { $lt: 30 } }).group({ _id: $age, count: { $sum: 1 } });docs.length; // 3docs.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 }</code><code class="language-javascript">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 }</code>
let docs = await Character.aggregate().match({ age: { $lt: 30 } }).group({ _id: $age, count: { $sum: 1 } });docs.length; // 3docs.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 }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 }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)
钩子。 您可以使用聚合中间件来转换聚合管道。
<code class="language-javascript">const characterSchema = Schema({ name: String, age: Number });characterSchema.pre(aggregate, function() {// Add a `$match` to the beginning of the pipelinethis.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; // 3docs.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 }</code><code class="language-javascript">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 }</code>
const characterSchema = Schema({ name: String, age: Number });characterSchema.pre(aggregate, function() {// Add a `$match` to the beginning of the pipelinethis.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; // 3docs.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 }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 }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 }
请登录后查看评论内容