first commit
This commit is contained in:
180
models/MarketPrice.js
Normal file
180
models/MarketPrice.js
Normal file
@@ -0,0 +1,180 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user