返回 AiToEarn
material.repository.ts
根目录 / project / aitoearn-backend / libs / mongodb / src / repositories / material.repository.ts
1 /*
2 * @Author: nevin
3 * @Date: 2024-06-17 19:19:15
4 * @LastEditTime: 2024-09-05 15:19:25
5 * @LastEditors: nevin
6 * @Description: Material material
7 */
8 import { Injectable } from '@nestjs/common'
9 import { InjectModel } from '@nestjs/mongoose'
10 import { UserType } from '@yikart/common'
11 import { FilterQuery, Model, RootFilterQuery } from 'mongoose'
12 import { Material, MaterialSource, MaterialStatus, MaterialType } from '../schemas'
13 import { BaseRepository } from './base.repository'
14
15 @Injectable()
16 export class MaterialRepository extends BaseRepository<Material> {
17 constructor(
18 @InjectModel(Material.name)
19 private readonly materialModel: Model<Material>,
20 ) {
21 super(materialModel)
22 }
23
24 override async create(newData: Partial<Material>) {
25 return await this.materialModel.create(newData)
26 }
27
28 // 批量删除
29 async deleteManyByIds(ids: string[], filter?: FilterQuery<Material>): Promise<boolean> {
30 const res = await this.materialModel.deleteMany({ _id: { $in: ids }, ...filter })
31 return res.deletedCount > 0
32 }
33
34 // 批量删除
35 async deleteByFilter(filter: FilterQuery<Material>): Promise<boolean> {
36 const res = await this.materialModel.deleteMany(filter)
37 return res.deletedCount > 0
38 }
39
40 async countByGroupId(groupId: string): Promise<number> {
41 return this.materialModel.countDocuments({ groupId })
42 }
43
44 async countByGroupIds(groupIds: string[]): Promise<Array<{ groupId: string, count: number }>> {
45 return this.materialModel.aggregate([
46 { $match: { groupId: { $in: groupIds } } },
47 { $group: { _id: '$groupId', count: { $sum: 1 } } },
48 { $project: { _id: 0, groupId: '$_id', count: 1 } },
49 ])
50 }
51
52 async countByFilterGroupedByGroupId(filter: FilterQuery<Material>): Promise<Array<{ groupId: string, count: number }>> {
53 return this.materialModel.aggregate([
54 { $match: filter },
55 { $group: { _id: '$groupId', count: { $sum: 1 } } },
56 { $project: { _id: 0, groupId: '$_id', count: 1 } },
57 ])
58 }
59
60 // 删除
61 async deleteByMinUseCount(groupId: string, minUseCount: number): Promise<boolean> {
62 const res = await this.materialModel.deleteMany({ groupId, useCount: { $gte: minUseCount } })
63 return res.deletedCount > 0
64 }
65
66 /**
67 * 更新状态
68 * @param id
69 * @param status
70 * @param message
71 * @returns
72 */
73 async updateStatus(
74 id: string,
75 status: MaterialStatus,
76 message: string,
77 ): Promise<boolean> {
78 const res = await this.materialModel.updateOne(
79 { _id: id },
80 { $set: { status, message } },
81 )
82 return res.modifiedCount > 0
83 }
84
85 async updateInfo(id: string, newData: Partial<Material>): Promise<boolean> {
86 const res = await this.materialModel.updateOne(
87 { _id: id },
88 { $set: newData },
89 )
90 return res.modifiedCount > 0
91 }
92
93 async getInfo(id: string) {
94 return await this.materialModel.findOne({ _id: id }).lean({ virtuals: true })
95 }
96
97 async getOptimalByGroup(groupId: string, type?: string, accountType?: string) {
98 const filter = {
99 groupId,
100 status: MaterialStatus.SUCCESS,
101 ...(type && { type }),
102 ...(accountType && { accountTypes: accountType }),
103 }
104
105 const [data = null] = await this.materialModel.aggregate([
106 { $match: filter },
107 { $sort: { useCount: 1 } },
108 {
109 $group: {
110 _id: null,
111 minUseCount: { $first: '$useCount' },
112 docs: { $push: '$$ROOT' },
113 },
114 },
115 {
116 $project: {
117 docs: {
118 $filter: {
119 input: '$docs',
120 cond: { $eq: ['$$this.useCount', '$minUseCount'] },
121 },
122 },
123 },
124 },
125 { $unwind: '$docs' },
126 { $replaceRoot: { newRoot: '$docs' } },
127 { $sample: { size: 1 } },
128 ])
129
130 return data
131 }
132
133 // 获取列表
134 async getList(
135 inFilter: {
136 userId?: string
137 userType?: UserType
138 title?: string
139 groupId?: string
140 status?: MaterialStatus
141 ids?: string[]
142 useCount?: number
143 },
144 pageInfo: {
145 pageNo: number
146 pageSize: number
147 },
148 ) {
149 const { pageNo, pageSize } = pageInfo
150
151 const filter: RootFilterQuery<Material> = {
152 ...(inFilter.userId && { userId: inFilter.userId }),
153 ...(inFilter.userType && { userType: inFilter.userType }),
154 ...(inFilter.title && {
155 title: { $regex: inFilter.title, $options: 'i' },
156 }),
157 ...(inFilter.groupId && { groupId: inFilter.groupId }),
158 ...(inFilter.status !== undefined && { status: inFilter.status }),
159 ...(inFilter.ids && { _id: { $in: [inFilter.ids] } }),
160 ...(inFilter.useCount !== undefined && { useCount: { $gte: inFilter.useCount } }),
161 }
162
163 const [total, list] = await Promise.all([
164 this.materialModel.countDocuments(filter),
165 this.materialModel
166 .find(filter)
167 .sort({ useCount: 1, createdAt: -1 })
168 .skip((pageNo! - 1) * pageSize)
169 .limit(pageSize)
170 .lean({ virtuals: true }),
171 ])
172
173 return {
174 total,
175 list,
176 }
177 }
178
179 // 获取列表
180 async listByIds(materialIds: string[], inFilter?: RootFilterQuery<Material>) {
181 const filter: RootFilterQuery<Material> = {
182 _id: {
183 $in: materialIds,
184 },
185 status: MaterialStatus.SUCCESS,
186 ...inFilter,
187 }
188 const list = await this.materialModel
189 .find(filter)
190 .sort({ useCount: 1, createdAt: -1 })
191 .lean({ virtuals: true })
192
193 return list
194 }
195
196 async tableListByIds(materialIds: string[], page: {
197 pageNo: number
198 pageSize: number
199 }, inFilter?: RootFilterQuery<Material>) {
200 const filter: RootFilterQuery<Material> = {
201 _id: {
202 $in: materialIds,
203 },
204 ...inFilter,
205 }
206
207 const [total, list] = await Promise.all([
208 this.materialModel.countDocuments(filter),
209 this.materialModel
210 .find(filter)
211 .sort({ useCount: 1, createdAt: -1 })
212 .skip((page.pageNo! - 1) * page.pageSize)
213 .limit(page.pageSize)
214 .lean({ virtuals: true }),
215 ])
216
217 return {
218 total,
219 list,
220 }
221 }
222
223 async getOptimalByIds(materialIds: string[]): Promise<Material | null> {
224 const data = await this.materialModel
225 .findOne({
226 _id: {
227 $in: materialIds,
228 },
229 status: MaterialStatus.SUCCESS,
230 })
231 .sort({ useCount: 1, createdAt: -1 })
232 .lean({ virtuals: true })
233
234 return data
235 }
236
237 async updateGroupIdByIds(ids: string[], targetGroupId: string, userId: string): Promise<number> {
238 const res = await this.materialModel.updateMany(
239 { _id: { $in: ids }, userId },
240 { $set: { groupId: targetGroupId } },
241 )
242 return res.modifiedCount
243 }
244
245 async listByIdsAndUserId(ids: string[], userId: string): Promise<Material[]> {
246 return this.materialModel.find({ _id: { $in: ids }, userId }).lean({ virtuals: true })
247 }
248
249 async listByGroupId(groupId: string): Promise<Material[]> {
250 return this.materialModel.find({
251 groupId,
252 status: MaterialStatus.SUCCESS,
253 }).lean({ virtuals: true })
254 }
255
256 // 增加草稿的使用次数,返回更新后的文档
257 async updateUseCountById(id: string): Promise<Material | null> {
258 const res = await this.materialModel.findOneAndUpdate(
259 { _id: id },
260 { $inc: { useCount: 1 } },
261 { new: true },
262 ).lean({ virtuals: true })
263 return res
264 }
265
266 // 减少草稿的使用次数(不低于 0)
267 async decrementUseCountById(id: string): Promise<boolean> {
268 const res = await this.materialModel.updateOne(
269 { _id: id, useCount: { $gt: 0 } },
270 { $inc: { useCount: -1 } },
271 )
272 return res.modifiedCount > 0
273 }
274
275 async listByUserIdAndTypeAndSourceAndStatusAndCreatedAt(
276 userId: string,
277 type: MaterialType,
278 source: MaterialSource,
279 status: MaterialStatus,
280 startAt: Date,
281 limit: number,
282 ): Promise<Material[]> {
283 return await this.materialModel.find({
284 userId,
285 type,
286 source,
287 status,
288 createdAt: { $gte: startAt },
289 }).sort({ createdAt: -1 }).limit(limit).lean({ virtuals: true })
290 }
291
292 async listUserIdsBySourceAndStatusAndUpdatedAt(source: MaterialSource, status: MaterialStatus, startAt: Date): Promise<string[]> {
293 return await this.materialModel.distinct('userId', {
294 source,
295 status,
296 updatedAt: { $gte: startAt },
297 }).exec()
298 }
299 }
300
300 lines TYPESCRIPT