ListingComment en services/api/src/models/ListingComment.js
Overview
Este archivo define el modelo persistente de comentarios para listings. Guarda comentarios raíz y respuestas en una sola colección, con soporte para moderación, sentimiento y contexto de ciclo de cuenta. El esquema usa timestamps: true y persiste en la colección listing_comments.
El modelo enlaza cada comentario con un Listing, con el usuario propietario del listing, con el autor del comentario y con un posible comentario padre. También conserva banderas de contexto para casos de protección, anonimización y purga del autor.
[!NOTE]
createdAtyupdatedAtse generan automáticamente por Mongoose cuandotimestamps: trueestá activo. El archivo no define esos campos manualmente.
How it works
erDiagram
Listing ||--o{ ListingComment : listingId
User ||--o{ ListingComment : ownerId
User ||--o{ ListingComment : authorId
User ||--o{ ListingComment : replyToUserId
ListingComment ||--o{ ListingComment : parentCommentId
ListingComment {
string listingId
string ownerId
string authorId
string parentCommentId
string replyToUserId
string text
string status
string moderationReason
string sentiment
boolean createdDuringProtection
boolean createdDuringAnonymization
string ownerStatusAtCreation
boolean authorPurged
date createdAt
date updatedAt
}
El esquema modela una conversación en hilo dentro de una única colección. listingId conecta el comentario con el anuncio, mientras que parentCommentId permite encadenar respuestas sobre otro comentario. ownerId y authorId apuntan a User, y replyToUserId identifica al destinatario de una respuesta cuando existe.
Key components
{
"title": "ListingComment",
"content": "Modelo de Mongoose que persiste comentarios de listings, respuestas en hilo, estado de moderaci\u00f3n, sentimiento y banderas de contexto de ciclo de cuenta.",
"type": "class",
"filePath": "services/api/src/models/ListingComment.js",
"badges": [
"public"
]
}
ListingCommentSchema define todos los campos del documento, sus referencias y sus restricciones. ListingCommentSchema.index(...) agrega los índices de lectura y unicidad. mongoose.model("ListingComment", ListingCommentSchema) registra y exporta el modelo.
Data & fields
El esquema usa referencias ObjectId, campos de estado y metadatos de moderación. También incluye banderas para conservar contexto histórico cuando cambian el estado del owner o el estado de purga del autor.
[
{
"name": "listingId",
"type": "Schema.Types.ObjectId",
"required": true,
"description": "Referencia obligatoria al Listing asociado. Está indexado."
},
{
"name": "ownerId",
"type": "Schema.Types.ObjectId",
"required": true,
"description": "Referencia obligatoria al User propietario del listing. Está indexado."
},
{
"name": "authorId",
"type": "Schema.Types.ObjectId",
"required": true,
"description": "Referencia obligatoria al User que escribió el comentario. Está indexado."
},
{
"name": "parentCommentId",
"type": "Schema.Types.ObjectId",
"description": "Referencia al comentario padre dentro de la misma colección. Por defecto es null y está indexado."
},
{
"name": "replyToUserId",
"type": "Schema.Types.ObjectId",
"description": "Referencia opcional al User destinatario de la respuesta. Por defecto es null."
},
{
"name": "text",
"type": "String",
"required": true,
"description": "Texto del comentario. Se recorta y tiene longitud máxima de 1000 caracteres."
},
{
"name": "status",
"type": "String",
"description": "Estado de moderación. Valores permitidos: visible, archived, removed. Valor por defecto: visible."
},
{
"name": "moderationReason",
"type": "String",
"description": "Razón de moderación. Se recorta y por defecto es una cadena vacía."
},
{
"name": "sentiment",
"type": "String",
"description": "Clasificación de sentimiento. Valores permitidos: positive, neutral, negative. Valor por defecto: neutral."
},
{
"name": "createdDuringProtection",
"type": "Boolean",
"description": "Marca si el comentario nació durante el ciclo de protección del owner. Conserva contexto histórico."
},
{
"name": "createdDuringAnonymization",
"type": "Boolean",
"description": "Marca si el comentario nació durante el proceso de anonimización del owner."
},
{
"name": "ownerStatusAtCreation",
"type": "String",
"description": "Estado del owner cuando se creó el comentario. Valores permitidos: active, pending_deletion, anonymized_pending_purge, purged, disabled."
},
{
"name": "authorPurged",
"type": "Boolean",
"description": "Marca si el autor fue purgado. La lectura puede sustituir el autor por Usuario eliminado."
},
{
"name": "createdAt",
"type": "date",
"description": "Marca temporal automática de creación. Solo lectura."
},
{
"name": "updatedAt",
"type": "date",
"description": "Marca temporal automática de última actualización. Solo lectura."
}
]
text es el único contenido obligatorio del comentario, y status y sentiment usan valores enumerados cerrados. Las banderas createdDuringProtection, createdDuringAnonymization, ownerStatusAtCreation y authorPurged guardan el contexto operativo del comentario sin depender del estado actual de los usuarios relacionados.
Estos campos no describen el contenido del comentario. Conservan información histórica para lecturas posteriores y procesos de purga.
createdDuringProtectionregistra si el comentario se creó durante el ciclo de protección de 60 días.createdDuringAnonymizationregistra si el comentario se creó durante la anonimización del owner.ownerStatusAtCreationfija el estado del owner en el momento de la creación.authorPurgedmarca que el autor fue purgado y que la lectura debe mostrar un autor eliminado.
Behaviors
Este archivo no define métodos propios de negocio. Su comportamiento relevante está en la construcción del esquema, en los índices y en el registro del modelo.
ListingCommentSchema.index({ listingId: 1, createdAt: -1 })— optimiza la lectura de comentarios de un listing en orden descendente de creación.ListingCommentSchema.index({ listingId: 1, parentCommentId: 1, authorId: 1 }, { unique: true, partialFilterExpression: { parentCommentId: { $type: "objectId" } } })— impone unicidad para respuestas conparentCommentIdválido.mongoose.model("ListingComment", ListingCommentSchema)— registra el modeloListingCommenten Mongoose y lo exporta para uso en otras capas.
Gotchas & edge cases
[!WARNING] La unicidad parcial solo aplica cuando
parentCommentIdtiene tipoobjectId. Eso significa que la regla protege respuestas encadenadas, no comentarios raíz. fileciteturn0file0turn0file15
[!NOTE]
replyToUserIdno está indexado. El esquema lo guarda como referencia opcional, pero no crea un índice específico para ese campo.
[!IMPORTANT] Los campos
createdDuringProtection,createdDuringAnonymization,ownerStatusAtCreationyauthorPurgedexisten para conservar contexto histórico. El archivo documenta su uso como soporte para estados posteriores del owner y del autor.
Related
Este modelo se conecta con Listing y User por medio de referencias ObjectId, y se refiere a sí mismo para soportar respuestas en hilo. También aparece como base de la ruta de comentarios de listings, que trabaja sobre el mismo contrato de datos. fileciteturn0file0turn0file5turn0file6
Listing— anuncio asociado al comentario.User— owner, author y posible destinatario de respuesta.ListingComment— comentario padre dentro del mismo hilo.services/api/src/modules/listing-comments/listing-comments.routes.js— consumo directo del modelo en la ruta de comentarios. fileciteturn0file5turn0file6