Files
nick-doc/02 - Data Models/Review.md
2026-05-23 20:35:34 +03:30

3.6 KiB

title, tags, aliases
title tags aliases
Review
data-model
mongoose
Rating
IReview

Review

Polymorphic 1-5 star review. The subjectType discriminator (seller or template) plus subjectId identifies what is being reviewed. sellerId is always present so per-seller aggregations work regardless of subject. A compound unique index on (subjectType, subjectId, reviewerId) prevents a reviewer from posting two reviews for the same subject.

[!note] Source backend/src/models/Review.ts:19 — schema definition backend/src/models/Review.ts:38 — model export

Schema

Field Type Required Default Validation Index Description
subjectType String yes enum: seller / template yes (compound) Discriminator.
subjectId ObjectId yes yes (compound) Id of the seller User or RequestTemplate.
sellerId ObjectId → User yes Seller associated with the review (always populated).
reviewerId ObjectId → User yes yes (compound + unique) Author.
rating Number yes min 1, max 5 Star rating.
comment String no "" maxlength 1000 Free-form comment.
isVerifiedBuyer Boolean no false Whether the reviewer actually bought from this seller.
purchaseRequestId ObjectId → PurchaseRequest no null Source request (if any).
status String no published enum: published / pending / rejected Moderation status.
createdAt Date auto yes (compound, desc) Mongoose timestamp.
updatedAt Date auto Mongoose timestamp.

Virtuals

None defined.

Indexes

Defined at backend/src/models/Review.ts:34-36:

  • { subjectType: 1, subjectId: 1, createdAt: -1 } — listing for a subject.
  • { reviewerId: 1, subjectType: 1 } — reviewer history.
  • { subjectType: 1, subjectId: 1, reviewerId: 1 }unique, one review per reviewer per subject.

Pre/Post Hooks

None declared.

Instance Methods

None defined.

Static Methods

None defined.

Relationships

  • References: User (sellerId, reviewerId, and subjectId when subjectType === 'seller'), RequestTemplate (subjectId when subjectType === 'template'), PurchaseRequest (purchaseRequestId).
  • Referenced by: none.

State Transitions

stateDiagram-v2
    [*] --> published : default
    [*] --> pending : moderation required
    pending --> published : approved
    pending --> rejected : rejected
    published --> rejected : flagged
    rejected --> [*]

Common Queries

// All reviews for a seller
Review.find({ subjectType: 'seller', subjectId: sellerUserId, status: 'published' })
      .sort({ createdAt: -1 });

// Average rating per seller
Review.aggregate([
  { $match: { subjectType: 'seller', subjectId: sellerUserId, status: 'published' } },
  { $group: { _id: null, avg: { $avg: '$rating' }, count: { $sum: 1 } } }
]);

// Reviews written by a user
Review.find({ reviewerId: userId }).sort({ createdAt: -1 });

// Reviews for a template
Review.find({ subjectType: 'template', subjectId: templateId, status: 'published' });

[!warning] Duplicate prevention Attempting to insert a second review for the same (subjectType, subjectId, reviewerId) will fail with a E11000 duplicate key error from MongoDB. Application code should treat that as "already reviewed".

Related: User, RequestTemplate, PurchaseRequest.