简化 MongoDB 聚合
Simplify MongoDB aggregation
我正在使用此类聚合按深层嵌套字段 ObjectId 对所有产品进行排序。
首先我填充了 catalogProduct 字段。
然后在 catalogProduct 中填充类别。
按类别 ID 对所有数据进行排序(return product if ids arr includes category._id)
倒序排序,return页,分页限制为8。
然后在没有分页和限制的情况下获取所有已排序产品的总数。
const sortedProducts = await StorageModel.aggregate([
// Unite products arr and totalCount of sorted products
{$facet: {
"sortedProducts": [
// populate catalogProduct ref by Id
{ $lookup: {
from: "catalogs",
localField: "catalogProduct",
foreignField: "_id",
as: "catalogProduct"
} },
// deconstruct this Arr, because we get only one Object
{ $unwind: "$catalogProduct" },
// populate category ref by Id inside catalogProduct object
{ $lookup: {
from: "categories",
localField: "catalogProduct.category",
foreignField: "_id",
as: "catalogProduct.category"
} },
// deconstruct this Arr, because we get only one Object
{ $unwind: "$catalogProduct.category" },
// returns product, if ids arr includes a catalogProduct.category._id
{ $match: {
"catalogProduct.category._id": { $in: ids }
} },
// sort in reverse order
{ $sort: { _id: -1 } },
// returns only *page
{ $skip: (page - 1) * 8 },
/// limit result by 8
{ $limit: 8 },
],
// total count for pagination, the same operations
"totalCount": [
{ $lookup: {
from: "catalogs",
localField: "catalogProduct",
foreignField: "_id",
as: "catalogProduct"
} },
{ $unwind: "$catalogProduct" },
{ $lookup: {
from: "categories",
localField: "catalogProduct.category",
foreignField: "_id",
as: "catalogProduct.category"
} },
{ $unwind: "$catalogProduct.category" },
{ $match: {
"catalogProduct.category._id": { $in: ids }
} },
// get total count of sorted data, without limit and pagination
{$count : "totalCount"},
]
}},
]);
products = sortedProducts[0].sortedProducts
totalProducts = sortedProducts[0].totalCount.totalCount
我得到这样的数据:
[
{ sortedProducts: [ [Object], [Object] ], totalCount: [ [Object] ] }
]
而且很好。但我认为,聚合可以简化,我不需要重复操作来获得总数,但我不知道如何。
您可以观察开始阶段,直到 $match
by catalogProduct.category._id
在 2 $facet
中重复。因此,你可以简单地将它们分解出来,然后将后面的阶段分别放入$facet
。
以下是我建议的代码版本:
StorageModel.aggregate([
{ $lookup: {
from: "catalogs",
localField: "catalogProduct",
foreignField: "_id",
as: "catalogProduct"
} },
// deconstruct this Arr, because we get only one Object
{ $unwind: "$catalogProduct" },
// populate category ref by Id inside catalogProduct object
{ $lookup: {
from: "categories",
localField: "catalogProduct.category",
foreignField: "_id",
as: "catalogProduct.category"
} },
// deconstruct this Arr, because we get only one Object
{ $unwind: "$catalogProduct.category" },
// returns product, if ids arr includes a catalogProduct.category._id
{ $match: {
"catalogProduct.category._id": { $in: ids }
} },
// Unite products arr and totalCount of sorted products
{$facet: {
"sortedProducts": [
// populate catalogProduct ref by Id
// sort in reverse order
{ $sort: { _id: -1 } },
// returns only *page
{ $skip: (page - 1) * 8 },
/// limit result by 8
{ $limit: 8 },
],
// total count for pagination, the same operations
"totalCount": [
// get total count of sorted data, without limit and pagination
{$count : "totalCount"},
]
}},
]);
我正在使用此类聚合按深层嵌套字段 ObjectId 对所有产品进行排序。
首先我填充了 catalogProduct 字段。
然后在 catalogProduct 中填充类别。
按类别 ID 对所有数据进行排序(return product if ids arr includes category._id)
倒序排序,return页,分页限制为8。
然后在没有分页和限制的情况下获取所有已排序产品的总数。
const sortedProducts = await StorageModel.aggregate([
// Unite products arr and totalCount of sorted products
{$facet: {
"sortedProducts": [
// populate catalogProduct ref by Id
{ $lookup: {
from: "catalogs",
localField: "catalogProduct",
foreignField: "_id",
as: "catalogProduct"
} },
// deconstruct this Arr, because we get only one Object
{ $unwind: "$catalogProduct" },
// populate category ref by Id inside catalogProduct object
{ $lookup: {
from: "categories",
localField: "catalogProduct.category",
foreignField: "_id",
as: "catalogProduct.category"
} },
// deconstruct this Arr, because we get only one Object
{ $unwind: "$catalogProduct.category" },
// returns product, if ids arr includes a catalogProduct.category._id
{ $match: {
"catalogProduct.category._id": { $in: ids }
} },
// sort in reverse order
{ $sort: { _id: -1 } },
// returns only *page
{ $skip: (page - 1) * 8 },
/// limit result by 8
{ $limit: 8 },
],
// total count for pagination, the same operations
"totalCount": [
{ $lookup: {
from: "catalogs",
localField: "catalogProduct",
foreignField: "_id",
as: "catalogProduct"
} },
{ $unwind: "$catalogProduct" },
{ $lookup: {
from: "categories",
localField: "catalogProduct.category",
foreignField: "_id",
as: "catalogProduct.category"
} },
{ $unwind: "$catalogProduct.category" },
{ $match: {
"catalogProduct.category._id": { $in: ids }
} },
// get total count of sorted data, without limit and pagination
{$count : "totalCount"},
]
}},
]);
products = sortedProducts[0].sortedProducts
totalProducts = sortedProducts[0].totalCount.totalCount
我得到这样的数据:
[
{ sortedProducts: [ [Object], [Object] ], totalCount: [ [Object] ] }
]
而且很好。但我认为,聚合可以简化,我不需要重复操作来获得总数,但我不知道如何。
您可以观察开始阶段,直到 $match
by catalogProduct.category._id
在 2 $facet
中重复。因此,你可以简单地将它们分解出来,然后将后面的阶段分别放入$facet
。
以下是我建议的代码版本:
StorageModel.aggregate([
{ $lookup: {
from: "catalogs",
localField: "catalogProduct",
foreignField: "_id",
as: "catalogProduct"
} },
// deconstruct this Arr, because we get only one Object
{ $unwind: "$catalogProduct" },
// populate category ref by Id inside catalogProduct object
{ $lookup: {
from: "categories",
localField: "catalogProduct.category",
foreignField: "_id",
as: "catalogProduct.category"
} },
// deconstruct this Arr, because we get only one Object
{ $unwind: "$catalogProduct.category" },
// returns product, if ids arr includes a catalogProduct.category._id
{ $match: {
"catalogProduct.category._id": { $in: ids }
} },
// Unite products arr and totalCount of sorted products
{$facet: {
"sortedProducts": [
// populate catalogProduct ref by Id
// sort in reverse order
{ $sort: { _id: -1 } },
// returns only *page
{ $skip: (page - 1) * 8 },
/// limit result by 8
{ $limit: 8 },
],
// total count for pagination, the same operations
"totalCount": [
// get total count of sorted data, without limit and pagination
{$count : "totalCount"},
]
}},
]);