Appearance
mongoose
aggregate
js
const [result] = await this.contentModel.aggregate([
// 筛选
{ $match: filter },
// 排序
{ $sort: { time: -1 } },
{
// 向文档添加新字段
$addFields: {
report: {
$cond: {
if: {
$or: [{ $not: ['$report'] }],
},
then: {
$concat: [
{ $substrCP: ['$content', 0, 80] },
{
$cond: {
if: { $gt: [{ $strLenCP: '$content' }, 50] },
then: '...',
else: '',
},
},
],
},
else: '$report',
},
},
},
},
{
// 在同一个聚合阶段内并行执行多个独立的子管道,并将所有结果合并输出到指定字段中
$facet: {
list: [
...paginationStages,
{
$project: {
_id: 1,
url: 1,
title: 1,
report: 1,
time: 1,
},
},
],
total: [{ $count: 'count' }],
},
},
]);init
js
async init(categories: CategoryInput[]) {
// 1. 获取所有待处理的分类名称
const allNames = categories.map(c => c.name);
// 2. 一次性查询已存在的分类(只返回名称,减少数据传输)
const existing = await this.categoryModel.find(
{ name: { $in: allNames } },
{ name: 1, _id: 1 }
).lean();
// 3. 建立已存在名称的 Set
const existingNames = new Set(existing.map(e => e.name));
// 4. 分离父分类和子分类,并过滤掉已存在的
const parentCategories: CategoryInput[] = [];
const childCategories: CategoryInput[] = [];
for (const cat of categories) {
if (!cat.parent) {
if (!existingNames.has(cat.name)) {
parentCategories.push(cat);
}
} else {
if (!existingNames.has(cat.name)) {
childCategories.push(cat);
}
}
}
// 如果没有新数据,直接返回
if (parentCategories.length === 0 && childCategories.length === 0) return;
try {
// 插入父分类
const insertedParents = await this.categoryModel.insertMany(parentCategories);
// 建立父分类名称到 _id 的映射
const parentNameToId = new Map(
insertedParents.map(p => [p.name, p._id])
);
// 准备子分类数据(将 parent 从名称替换为 ObjectId)
const childDocs: CategoryDoc[] = [];
for (const child of childCategories) {
const parentId = parentNameToId.get(child.parent!);
if (!parentId) {
// 如果父分类不在本次插入中,则从数据库查询
const existingParent = await this.categoryModel.findOne(
{ name: child.parent },
{ _id: 1 },
).lean();
if (!existingParent) {
throw new Error(`父分类 "${child.parent}" 不存在`);
}
childDocs.push({ name: child.name, slug: child.slug, parent: existingParent._id as Types.ObjectId });
} else {
childDocs.push({ name: child.name, slug: child.slug, parent: parentId as Types.ObjectId });
}
}
// 插入子分类
if (childDocs.length > 0) {
await this.categoryModel.insertMany(childDocs);
}
} catch (error) {
throw error;
} finally {
}
}