reddit comment system how to replicate in mongodb/nodejs - node.js

How do I make nested comment replies in MongoDB/mongoose to create a comment system like in reddit nesting. Here are my schemas i created so far:
var CommentSchema = Schema({
body: {type: String},
chapterId: {type: RK, ref: 'Chapter'},
by: {type: RK, ref: 'User'},
}, {timestamps: true});
var UserSchema = new Schema({
name: String,
username: {type:String, unique: true},
profile_pic: String,
password: String,
role:{type: [{
type: String,
enum: ['user', 'admin']
}],
default: ['user']
}
});

Related

How to create a mongoose sub model without creating a collection for it

const walletTransactionSchema = new mongoose.Schema({
a: {type: Boolean, required: true},
},
{timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}});
const walletSchema = new Schema({
b: {type: Boolean, required: true},
transactions: [{type: walletTransactionSchema}],
});
walletSchema.index({'transactions': 1}, {sparse: true});
module.exports.Wallet = mongoose.model('Wallet', walletSchema, 'wallets');
module.exports.WalletTransaction = mongoose.model('WalletTransaction', walletTransactionSchema);
I'm trying to create a model for a subdocument (WalletTransaction) without creating a collection for it. Unfortunately mongoose is automatically creating that collection. How can I prevent that behavior and just define a sub-model without creating a collection. I prefer to organize my schemas by refactoring them instead of just embedding them.
I used to do this without trouble with above definitions. I guess after updating to mongoose 6.0.8 (from 5.13) this is happend.
if you wanna create another model inside a model
You should go with the following approach
const mongoose = require('mongoose');
const userSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
email: {
type: String,
required: true},
about:{type:String},
password: {type: String, required: true},
friends: [new mongoose.Schema({
user: {type: String}
}, {strict: false})],
profileImage: {type: String, default: "default.jpg"},
userName: {type: String, required: true},
matches: {type: Number, default: 0},
wins: {type: Number, default: 0},
losses: {type: Number, default: 0},
backgroundImage: {type: String, default: "default.jpg"},
resetPasswordToken: {type: String, required: false},
resetPasswordExpires: {type: Date, required: false},
isDeleted: {type: Boolean, default: false},
deletedAt: {type: Date, default: null},
}, {timestamps: true}, {strict: false});
module.exports = mongoose.model('User', userSchema);
Like this I create another model in my User model with name Friends in which each entry has one specific id

Mongoose populate followers same document

I need to populate ObjectId parameters from the same Schema of users What am trying to do is I have 'Users' document and each record has followers and the ref is the same schema of users.
var userSchema = new Schema({
username: {type: String, unique: true, trim: true},
password: {type: String},
email: {type: String, trim: true},
avatar: {type: String},
fullname: {type: String},
bio: {type: String},
phone: {type: Number},
country: {type: String},
postal: {type: Number},
followers: [{ type: Schema.ObjectId, ref: 'User' }],
followed: [{ type: Schema.ObjectId, ref: 'User' }],
registered: {type: Date, default: Date.now}
});
var User = mongoose.model('users',userSchema);
Now when I tried to print the user information followers array return with ObjectId not the whole information
I try to print with this snippet
User.find().exec(function(error, groups) {
return res.status(200).send(groups);
});
What you want to achieve here is
User.find({})
.populate('followers')
.populate('followed')
.then(users => {
})
This will populate with both the followers and followed with their respective user objects

Populate nested array with Mongoose

I have a user schema as shown below and I'm trying to populate the live projects array but I can't figure out how to access it.
const userSchema = new Schema({
local: {
email: String,
username: String,
password: String,
liveProjects: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'liveProject'
}]
},
google: {
googleId: String,
email: String,
username: String,
liveProjects: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'liveProject'
}]
}
});
const User = mongoose.model('user', userSchema);
module.exports = User;
If it wasn't embedded I could just use
User.findById(id).populate('liveProjects').exec((err,projects)=>{});
But how do I get access to 'local.liveProjects' or 'google.liveProjects' so that I can populate them?
Turns out it is just as simple as
User.findById(id).populate('local.liveProjects').exec((err,projects)=>{});
User Schema Here
`let UserSchema = new Schema({
email: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
profile: {
firstName: {type: String,required: true},
lastName: {type: String,required: true},
address1: {type: String},
address2: {type: String},
city: {type: String},
state: {type: String},
zip: {type: String},
phone: {type: String,required: true},
avatar:{ type: Schema.Types.ObjectId, ref: 'Avatar'},
shippingAddress:{
address1: {type: String},
address2: {type: String},
city: {type: String},
state: {type: String},
zip: {type: String}
},
},
redemptionCards : [{ type: Schema.Types.ObjectId, ref: 'CardCodes' }]
});`
Logic to get RedemptionCards:-
User.findOne({ email }).populate("redemptionCards")
.exec(function (err, user) {
CardData.populate(user.redemptionCards, {path: 'redemptionCards',match: { _id: { $ne: null }}}, function (err, cards) {
console.log(cards);
});
FYI - CardData is the Hardcoded JSON file. Hope this helps.

Unique index on nested fields in Mongoose schema

Are these schemas valid?
var StudentSchema = new mongoose.Schema({
first_name: {type: String, required:true},
last_name: {type: String, required: true},
mother_name : {type: String, required: true},
siblings:[{
name:{type: String, required: true},
age:{type:Number, required: true},
school:{type:String, required:true}
}]
});
And this
var WinSchema = new mongoose.Schema({
event:{type: mongoose.Schema.Types.ObjectId, ref:'Event'},
winners : [{
student: {type: mongoose.Schema.Types.ObjectId, ref: 'Student'},
position: {type:String, enum:["First","Second","Third","Consolation"]}
}]
});
WinSchema.index({event:1,winners.student:1},{unique:true});
mongoose.model('Win',WinSchema);
Can we nest it as shown in StudentSchema?
Can we create a unique index on nested documents?
Yes you can nest it, see schema example here and of course you can create a index on nested documents here is the example.

about mongoose populate relation a string field

I have two Schema
1 - User
UserSchema = new db.Schema({
email: {type: String, required: true},
pass: {type: String, required: true},
nick: {type: String, required: true},
admin: {type: String, default: ''},
reg: {type: Date, default: Date.now}
});
2 - Article
ArticleSchema = new db.Schema({
title: {type: String, required: true},
alise: {type: String},
time: {type: Date, defaults: Date.now},
view: {type: Number, defaults: 0},
author: {type: String},
content: {type: String},
classes: {type: db.Schema.Types.ObjectId, ref: 'Classes'},
user: {type: String, ref: 'User'}
});
I want ArticleSchema user field relation UserSchema nick.
my code:
Model.findOne({}).populate('classes user').exec(function(err, res){
if(err){
cb(err);
}else{
cb(null, res);
}
});
This is not working
message: 'Cast to ObjectId failed for value "tudou" at path "_id"'
What should I do?
Apparently you are using Mongoose, right?
If yes, to do it you must use db.Schema.Types.ObjectId in the ArticleSchema user field. So, your ArticleSchema should looks like this:
ArticleSchema = new db.Schema({
title: {type: String, required: true},
alise: {type: String},
time: {type: Date, defaults: Date.now},
view: {type: Number, defaults: 0},
author: {type: String},
content: {type: String},
classes: {type: db.Schema.Types.ObjectId, ref: 'Classes'},
user: {type: db.Schema.Types.ObjectId, ref: 'User'}
});
According to documentation:
There are no joins in MongoDB but sometimes we still want references to documents in other collections. This is where population comes in.
So, taking a look here, we can do something like that:
//To create one user, one article and set the user whos created the article.
var user = new UserSchema({
email : 'asdf#gmail.com',
nick : 'danilo'
...
});
user.save(function(error) {
var article = new ArticleSchema({
title : 'title',
alise : 'asdf',
user : user,
...
});
article.save(function(error) {
if(error) {
console.log(error);
}
});
}
And to find an article that was created for danilo:
ArticleSchema
.find(...)
.populate({
path: 'user',
match: { nick: 'danilo'},
select: 'email nick -_id'
})
.exec()
I suggest you to read about mongoose populate here
As of 4.5.0 You can use populate virtuals : http://mongoosejs.com/docs/populate.html#populate-virtuals
UserSchema = new db.Schema({
email: {type: String, required: true},
pass: {type: String, required: true},
nick: {type: String, required: true},
admin: {type: String, default: ''},
reg: {type: Date, default: Date.now}
});
ArticleSchema = new db.Schema({
title: {type: String, required: true},
alise: {type: String},
time: {type: Date, defaults: Date.now},
view: {type: Number, defaults: 0},
author: {type: String},
content: {type: String},
classes: {type: db.Schema.Types.ObjectId, ref: 'Classes'},
user: {type: String}
});
ArticleSchema.virtual('_user', {
ref: 'User', // The model to use
localField: 'user', // Find people where `localField`
foreignField: 'email', // is equal to `foreignField`
// If `justOne` is true, 'members' will be a single doc as opposed to
// an array. `justOne` is false by default.
justOne: true,
options: { sort: { name: -1 }, limit: 5 }
});
var User = mongoose.model('User', UserSchema);
var Article = mongoose.model('Article', ArticleSchema);
Article.find({}).populate('_user').exec(function(error, articles) {
/* `articles._user` is now an array of instances of `User` */
});

Resources