MongoDB Follow/Unfollow Schema Design - mongodb

I'm working on a follow/unfollow feature, where I need to design mongodb schema.
Users can follow, users, posts, pages etc. They can obviously unfollow as well.
I came up with following schema:
{
created: {
type: Date,
default: Date.now
},
contentType: {
type: String,
required: false,
trim: true
},
contentId: {
type: Schema.ObjectId,
required: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
}
My question is how can I track the unfollow case, shall I add a deleted: Date and always create a new entry for follow action. or shall I create updateHistory: Array to keep track of all follow/unfollow actions. What schema is better to go with.
Thanks.

The way I solved it is using SoftDelete. I always create a new record for follow and if some unfollow again then I added deleted: Date. This way I kept track follow/unfollow history.

Related

Mongoose one-to-many relationship not being populated

I have a one-to-many relationship where a place can have multiple reviews. Here are the 2 schemas
export const PlaceSchema = new mongoose.Schema({
name: { type: String, required: true, unique: true },
center: { type: [Number], required: true },
borders: { type: [], required: true },
reviews: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Review' }]
});
export const ReviewSchema = new mongoose.Schema({
user: { type: String, required: true },
city: { type: mongoose.Schema.Types.ObjectId, ref: 'Place', required: true },
creation_date: { type: Date, required: true },
...
});
I have reviews with correct place ID. But when I do a simple this.placeModel.find().populate('reviews').exec(), the reviews always come back as an empty array. But the IDs seem to be fine, as visible here (place on the left, review on the right)
It's my first side project where I play with with Mongo, so I don't really see what I'm missing.
Your query this.placeModel.find().populate('reviews').exec() will work in this manner:
Find all place documents from the places collection.
For each place document, iterate through the reviews field (of array type) and search for the document in the reviews collection with the matching id, and replace the array element with the review document.
Return the list of place documents where the reviews field has been populated with the review documents.
Hence, you need to ensure that your place documents contain the correct id of the review documents in the reviews field instead of ensuring that you have the correct place id in the review documents for the query you want to execute.

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?

Is there a way to selectively apply timestamps in mongoose schema?

I'm currently designing a mongoose Schema. The schema is for blog comments, it looks like this:
new mongoose.Schema({
commentedOn: {
type: mongoose.Schema.Types.ObjectId,
required: true
},
author: {
type: String,
required: true
},
contents:{
type: String
},
points: {
type: Number,
default:0
},
timestamps: true
})
The points field is to record the votes of one comment. I don't want to change the timestamp every time when users vote the comment. Is there a way to achieve this? Or should I move the points field out of this schema?
I believe timestamps should be passed in the second argument of the schema.
Regarding your question, the only way I can think of doing this is to not use timestamps and explicitly declare your timestamp fields e.g. createdAt and updatedAt in your schema. Whenever you save or update, you would explicitly set the updatedAt field (or not) depending on the situation.
new mongoose.Schema({
commentedOn: { type: mongoose.Schema.Types.ObjectId, required: true },
author: { type: String, required: true },
contents: String,
points: { Number, default: 0 },
createdAt: { type: Date, default: Date.now },
updatedAt: Date
});

Modelling many-to-many relationships in MongoDB

I am having difficulty coming up with schemas for a school app.
In particular, I am trying to model the relationship between the different kinds of users (e.g. instructors, teaching assistants, and students) with the courses and tutorials that they belong to.
Here are my requirements:
each course will have one to many tutorials;
each course will be taught by one to many instructors;
each course will have one to many students;
each tutorial will have one to many teaching assistants;
each instructor will teach one to many courses;
each teaching assistant may have one to many tutorials in one to many course;
each student will be enrolled in one to many courses;
each student may belong to one tutorial in the course that they are enrolled in;
So far, the following are my schemas for the user, course, and tutorial collections.
var CourseSchema = new mongoose.Schema({
name: { type: String, required: true },
code: { type: String, required: true },
tutorials: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Tutorial' }], // 1
instructors: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }], // 2
students: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }] // 3
});
var TutorialSchema = new mongoose.Schema({
number: { type: String, required: true },
teachingAsst: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }] // 4
});
var UserSchema = new mongoose.Schema({
email: { type: String, lowercase: true },
password: String,
name: {
first: { type: String, lowercase: true },
last: { type: String, lowercase: true }
},
roles: [String] // instrutor, teachingAsst, student
};
The problem lies with my requirements 5 to 8 -- which is more so the relationship from the User to the other models. What could be a good way to model these relationships?
One way, I thought of doing it e.g. req 5 was to add a field to the User schema
instructor: {
courses: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Course' }]
}
But the problem happens when I do e.g. req 6. similarly because it will complicate the queries (e.g. "find all the tutorials in a course that the user is a teaching assistant in").
teachingAsst: {
courses: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Course' }]
tutorials: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Tutorial' }]
}
In your case, Design is many to many relations. So you have two approach for your problem.
Reference Document
Embedded Document
Embedded approach will have duplicate data which is difficult to update and delete where as the read operation will be much efficient due to single query.
In case of the Reference Approach, your data will be demoralized. So, update and delete operation will be easy where as the read operation will have multiple hits on the database.
So, based on the your application requirement you should have to decide the appropriate approach.

How to model a pending trade in MongoDB?

I'm wondering what the "Mongo Way" is for modeling a pending trade of an item between two users.
I have a user collection and I have a book collection. In my app, the users will be able to propose trades to one another. Until the trade proposal is accepted, the trade needs to be stored as a pending trade in the database.
It seems to me that the best option is to have a 'trades' property on each book document modeled like this (using Mongoose):
const booksSchema = new Schema({
title: { type: String, required: true },
createdAt: { type: Date, 'default': Date.now },
updatedAt: { type: Date, 'default': Date.now },
author: { type: String, required: false},
imageUrl: { type: String, required: false},
ownerUser: { type: Schema.ObjectId, required: true },
trades: [{
fromUser: { type: Schema.ObjectId, required: true },
bookOffered: { type: Schema.ObjectId, required: true }
}]
});
The problem I see with this is that it will involve updating two documents when the trade is accepted. Assuming that the trade is accepted, the ownerUser on each document will need to be changed and the trades array will need to be cleared out.
It seems that to do this you'd want the changes to be in some sort of "Transaction" so that if one didn't update for some reason, then the other wouldn't either.
Is this a typical way to model this type of situation? What to do about the "Transaction" part of the situation?
There is no way to do a transaction including multiple documents in MongoDB.
You might consider a separate Trade collection with documents like:
{
book: ...,
ownerUser: ...,
buyerUser: ...,
status: 'pending'
dateSold: null
}
When the trade is approved you can change this document first, then update any related documents next. Should something else fail, this document would decide whether the transaction had actually happened.