import mongoose from "mongoose"; /** * MarketPrice Model * Stores reference prices from Steam market for quick lookups * Used when loading inventory or updating item prices */ const marketPriceSchema = new mongoose.Schema( { // Item name (market_name from Steam API) name: { type: String, required: true, index: true, }, // Game identifier game: { type: String, required: true, enum: ["cs2", "rust"], index: true, }, // Steam App ID appId: { type: Number, required: true, index: true, }, // Market hash name (unique identifier from Steam) marketHashName: { type: String, required: true, unique: true, }, // Price in USD price: { type: Number, required: true, min: 0, }, // Type of price used (safe, median, mean, avg, latest) priceType: { type: String, enum: ["safe", "median", "mean", "avg", "latest"], default: "safe", }, // Item image URL image: { type: String, default: null, }, // Border color (rarity indicator) borderColor: { type: String, default: null, }, // Steam name ID nameId: { type: Number, default: null, }, // Last updated timestamp lastUpdated: { type: Date, default: Date.now, index: true, }, }, { timestamps: true, collection: "marketprices", } ); // Compound indexes for fast lookups marketPriceSchema.index({ game: 1, name: 1 }); marketPriceSchema.index({ game: 1, marketHashName: 1 }); marketPriceSchema.index({ game: 1, price: -1 }); // For sorting by price marketPriceSchema.index({ lastUpdated: -1 }); // For finding outdated prices // Static method to find price by market hash name marketPriceSchema.statics.findByMarketHashName = async function ( marketHashName, game = null ) { const query = { marketHashName }; if (game) query.game = game; return await this.findOne(query); }; // Static method to find price by name (partial match) marketPriceSchema.statics.findByName = async function (name, game = null) { const query = { $or: [ { name: name }, { name: { $regex: name, $options: "i" } }, { marketHashName: name }, { marketHashName: { $regex: name, $options: "i" } }, ], }; if (game) query.game = game; return await this.find(query).limit(10); }; // Static method to get items by game marketPriceSchema.statics.getByGame = async function (game, options = {}) { const { limit = 100, skip = 0, minPrice = 0, maxPrice = null } = options; const query = { game }; if (minPrice > 0) query.price = { $gte: minPrice }; if (maxPrice) { query.price = query.price || {}; query.price.$lte = maxPrice; } return await this.find(query) .sort({ price: -1 }) .limit(limit) .skip(skip); }; // Static method to get price statistics marketPriceSchema.statics.getStats = async function (game = null) { const match = game ? { game } : {}; const stats = await this.aggregate([ { $match: match }, { $group: { _id: null, count: { $sum: 1 }, avgPrice: { $avg: "$price" }, minPrice: { $min: "$price" }, maxPrice: { $max: "$price" }, totalValue: { $sum: "$price" }, }, }, ]); return stats[0] || { count: 0, avgPrice: 0, minPrice: 0, maxPrice: 0, totalValue: 0, }; }; // Instance method to check if price is outdated marketPriceSchema.methods.isOutdated = function (hours = 24) { const now = new Date(); const diff = now - this.lastUpdated; const hoursDiff = diff / (1000 * 60 * 60); return hoursDiff > hours; }; // Instance method to update price marketPriceSchema.methods.updatePrice = async function (newPrice, priceType) { this.price = newPrice; if (priceType) this.priceType = priceType; this.lastUpdated = new Date(); return await this.save(); }; const MarketPrice = mongoose.model("MarketPrice", marketPriceSchema); export default MarketPrice;