181 lines
4.0 KiB
JavaScript
181 lines
4.0 KiB
JavaScript
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;
|