Data modelling using mongoose for sports bet tracking application - mongodb

I built a simple sports bet tracker application while I am learning the MERN stack. Users can track their sports bets and see various stats on their performance. It currently only supports tracking single bets (1 selection in bet) and I wish to add to ability to track multiple bets (>1 selections in bet). Each selection in a multiple bet will have the same data as a single bet eventDate, sport, event, selection odds etc. I'm just looking for some advice on the best way to add this in. Bet model currently is as follows
const betSchema = mongoose.Schema({
eventDate: {
type: Date
},
sport: {
type: String
},
event: {
type: String
},
market: {
type: String
},
selection: {
type: String
},
odds: {
type: Number
},
result: {
type: String,
default: 'Pending'
},
stake: {
type: Number
},
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
}
}, {
timestamps: true
})
Going forward a bet can have one selection or many in it so I was thinking this should become an array. If it has one selection the odds for the bet will be the odds of that selection but if it has multiple selections in it the odds of the bet will be the odds of the selections multiplied. If one selection in a multiple bet loses the bet is a loss. I was thinking something like the following setup but I'm not sure as I don't have much database experience any help who'd be appreciated.
const betSchema = mongoose.Schema({
selections: [{
sport: {
type: String
},
event: {
type: String
},
eventDate: {
type: Date
},
market: {
type: String
},
selection: {
type: String
},
result: {
type: String
},
odds: {
type: Number
},
}],
odds: {
type: Number
},
stake: {
type: Number
},
result: {
type: String,
default: 'Pending'
},
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
}
}, {
timestamps: true
})

I went with the Schema shown in the question, not sure if it's the best solution but it works for what I am trying to build.

Related

Pushing into array mongoose and mongo

I get the following error Cannot create field 'likes' in element whenever I am trying to push into my likeList array nested inside my comments.
When executing the following:
Feed.findOneAndUpdate(
{
owner: req.body.authorId,
"posts.comments.commentList._id": req.body.commentId
},
{
$push: {
"posts.$.comments.commentList.likes.likeList": {
user: req.user._id,
avatar: req.user.profile.profile_picture.url,
name: req.user.name
}
)
And my schema is as follows:
Feed Schema
owner: {
type: Schema.Types.ObjectId,
ref: "userType"
},
posts: [
{
author: {
userType: {
type: String,
enum: ["IndustryPartner", "User", "School"]
},
user: {
type: Schema.Types.ObjectId,
ref: "posts.author.userType", //<- This may cause an issue, if there are any issues with retrieving user fields, CHECK THIS
required: true
},
name: { type: String, required: true },
avatar: { type: String, required: true }
},
comments: {
totalComments: { type: Number, default: 0 },
commentList: [
{
likes: {
totalLikes: { type: Number, default: 0 },
likeList: [ <---//Trying to push here
{
user: { type: Schema.Types.ObjectId, ref: "User" },
avatar: { type: String },
name: { type: String },
date: {
type: Date,
default: Date.now
}
}
]
...
I am not sure if it's an issue with the query I am using in the first parameter to filter.
Update entire error message
It is odd because it appears that it is actually finding the correct commentList to go to, but is unable to access the likes field within the array itself. Am I wrong assuming that this should be able to step through it? posts.$.comments.commentList.likes.likeList
{ MongoError: Cannot create field 'likes' in element {commentList: [ { likes: { totalLikes: 0, likeList: [] },
_id: ObjectId('5cf6b3293b61fe06f48794e3'), user: ObjectId('5c9bf6eb1da18b038ca660b8'), avatar: "https://sli.blob.core.windows.net/stuli/
profile-picture-e1367a7a-41c2-4ab4-9cb5-621d2008260f.jpg", name: "Luke Skywalker", text: "Test comment from Luke", repliesToComment: [], date: new Date(1559671593009) } ]}
After further research, it appears the positional operator is no longer useful after stepping through 2 levels of arrays. So, the solution would be to use JS to change push the values into the array and then save them.

mongo db schema relational or in collection

I am working on a side project at the moment that will hopefully help understand Mongo. I am coming from a MySQL world so some of the concepts are a bit strange to me at minutes.
My side project is essentially a project organiser, a project can have 3 areas where a a user can upload multiple files/images, project assests, work in progress, and deliverables.
So should I be creating collections for assets, wip and deliverables and then link them to the project? Using some like,
type: Schema.Types.ObjectId,
ref: "projects"
Or should they be part of the projects schema giving each file a type instead making the project schema look something like,
// Create schema
const ProfileSchema = new Schema({
name: {
type: String,
required: true
},
owner: {
type: Schema.Types.ObjectId,
ref: "users"
},
slug: {
type: String,
required: true,
max: 40
},
status: {
type: String,
required: true
},
brief: {
type: String,
default: "No brief given"
},
date_due: {
type: Date
},
created_at: {
type: Date,
default: Date.now
},
files: [
name: {
type: String
},
filepath: {
type: String
},
type: {
type: String
}
]
});
Potentially there will be 1000s of rows in the collection if I were to ever launch the tool
Is there an accepted way of doing what would ordinarily be an 1:n relationship in a relational database?

How to make sure there is no duplicate data on model's keys?

This is my user model:
const UserSchema = new mongoose.Schema(
{
email: { type: String, required: true, unique: true },
watched: [{ type: String}],
watchLater: [{ type: String}],
},
{ timestamps: true },
)
there is watched and watchLater array which contains strings. When I add a string to watched I want to remove or make sure there is no same string on watchLater and vice versa. What's the best approach for this? Do I have to query both keys separately, compare, and write back to the database or there is some other way?
You can put the criteria in query part
db.collection.update(
{ watched: { $ne: string } watchedLater: { $ne:string }},
{ $push: { watched: string }}
)

database design for a market

I want to design database for a market with simple and few objects for selling using NodeJS, MongoDB and Mongoose. Because I'm new to MongoDB and NoSQL designs, I need a guide for designing it.
My implementation is here:
var orderSchema = new Schema({
orderId: Schema.Types.ObjectId,
orderType: {
type: String, enum: ['OBJEC1',
'OBJECT2',
//other objects
], default: 'ALBUM'
},
price: { type: String, enum: ['PRICE1', 'PRICE2', 'PRICE3'] },
coverPhoto: { type: String, default: '' },
photos: [{
address: { type: String, default: 'media/uploads' },
}],
orderQuantity: { type: Number, default: 1 },
isChecked: { type: Boolean, default: true },
date: { type: Date, default: Date.now }
});
Besides, I'll save reference of each order to its related user. Am I right, or not? Thanks a lot.
The way you designed your schema based on the logic seems good. One thing is you have used default in all the fields.
First, you should understand that default is optional and default is used only when you want to populate some value during the data is created.
Example: you have default for date field, here it is good to have. You don't want to manually assign a date during processing the data. So only unless your field should have common default value when creation then you go ahead otherwise remove the default field and make sure the data is inserted properly.
you can use required attribute in case some field is mandatory to create a document in the collection. I guess orderType a mandatory field so don't miss it ever during insertion so make it as required: true.
var orderSchema = new Schema({
orderId: {
type: Schema.Types.ObjectId
},
orderType: {
type: String,
enum: ['OBJEC1','OBJECT2']
},
price: {
type: String,
enum: ['PRICE1', 'PRICE2', 'PRICE3']
},
coverPhoto: {
type: String
},
photos: [{
address: {
type: String
}
}],
orderQuantity: {
type: Number
},
isChecked: {
type: Boolean,
default: true
},
date: {
type: Date,
default: Date.now
}
});

Populate query with match returns null

I have three schemas, that need them to be separated and I can't use subdocuments. The important one is this
export var TestSchema = new mongoose.Schema({
hash: { type: String, index: { unique: true }, default: common.randomHash },
date: { type: Date, default: Date.now },
result: { type: Object },
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
data: { type: Object },
finished: Date,
lang: { type: String, default: 'pt' },
benchmark: { type: String, required: true },
order: { type: mongoose.Schema.Types.ObjectId, ref: 'Transaction' },
/* TODO: remove */
name: { type: String }
});
I have a query that does the populate (it's actually a pagination helper, but I'm cutting to the chase):
TestModel.find({hide: {$ne: true}, user: id}).populate({
path: 'user',
match: {$or: [
{email: new RegExp(search, i)},
{name: new RegExp(search, i)},
{empresa: new RegExp(search, i)},
]}
}).exec().then(/*...*/)
when populate.match doesn't find anything, it sets the user to null. I tried setting the find({'user':{$ne: null}}) but it ignores it. (I guess the populate happen after the find call, maybe that's the reason).
Is there any way I can filter it in the database layer instead having to rely on iterating of the results, check for null then filter out?
This answer on GitHub clarifies that it is not possible with populate, due to how MongoDB works. However, you should be able to do it with $lookup.