ad.js•4.12 kB
/**
* Ad model
* Stores information about Facebook ads
*/
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const adSchema = new Schema({
// Facebook ad ID
adId: {
type: String,
required: true,
unique: true,
index: true
},
// Ad name
name: {
type: String,
required: true
},
// Ad set this ad belongs to
adSetId: {
type: String,
required: true,
index: true
},
// User who owns this ad
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
index: true
},
// Ad status
status: {
type: String,
enum: ['ACTIVE', 'PAUSED', 'DELETED', 'ARCHIVED'],
default: 'PAUSED'
},
// Creative information
creativeId: {
type: String
},
// Creative details
creative: {
// Creative type
type: {
type: String,
enum: ['IMAGE', 'VIDEO', 'CAROUSEL', 'COLLECTION', 'SLIDESHOW'],
required: true
},
// Title and text
title: {
type: String
},
body: {
type: String
},
// Call to action
callToAction: {
type: String
},
// URL parameters
url: {
type: String
},
urlParams: {
type: Schema.Types.Mixed
},
// Media assets
imageUrl: {
type: String
},
videoUrl: {
type: String
},
// Carousel items
carouselItems: [{
title: String,
description: String,
imageUrl: String,
url: String
}],
// Additional creative details
additionalDetails: {
type: Schema.Types.Mixed
}
},
// Preview URL
previewUrl: {
type: String
},
// Ad performance metrics (cached)
metrics: {
impressions: {
type: Number,
default: 0
},
clicks: {
type: Number,
default: 0
},
spend: {
type: Number,
default: 0
},
conversions: {
type: Number,
default: 0
},
ctr: {
type: Number,
default: 0
},
cpc: {
type: Number,
default: 0
},
cpm: {
type: Number,
default: 0
},
reach: {
type: Number,
default: 0
},
frequency: {
type: Number,
default: 0
},
costPerConversion: {
type: Number,
default: 0
},
conversionRate: {
type: Number,
default: 0
},
roas: {
type: Number,
default: 0
},
engagement: {
type: Number,
default: 0
},
videoViews: {
type: Number,
default: 0
},
videoWatchTime: {
type: Number,
default: 0
}
},
// Timestamps
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
},
// Last sync with Facebook
lastSyncedAt: {
type: Date,
default: Date.now
}
}, {
timestamps: true
});
// Indexes for faster queries
adSchema.index({ adId: 1 });
adSchema.index({ adSetId: 1 });
adSchema.index({ userId: 1 });
adSchema.index({ status: 1 });
adSchema.index({ createdAt: -1 });
adSchema.index({ 'creative.type': 1 });
/**
* Find ads by user ID
*/
adSchema.statics.findByUserId = function(userId) {
return this.find({ userId });
};
/**
* Find ads by ad set ID
*/
adSchema.statics.findByAdSetId = function(adSetId) {
return this.find({ adSetId });
};
/**
* Find active ads
*/
adSchema.statics.findActive = function() {
return this.find({ status: 'ACTIVE' });
};
/**
* Find ad by Facebook ad ID
*/
adSchema.statics.findByAdId = function(adId) {
return this.findOne({ adId });
};
/**
* Find ads by creative type
*/
adSchema.statics.findByCreativeType = function(type) {
return this.find({ 'creative.type': type });
};
/**
* Update ad metrics
*/
adSchema.methods.updateMetrics = function(metrics) {
this.metrics = { ...this.metrics, ...metrics };
return this.save();
};
/**
* Update last synced timestamp
*/
adSchema.methods.updateLastSynced = function() {
this.lastSyncedAt = Date.now();
return this.save();
};
const Ad = mongoose.model('Ad', adSchema);
module.exports = Ad;