Modeling with MongoDB and Mongoose - mongodb

I have a simple app which lists tour guides and reviews left by users about each guide. Any user can give be a guide and can give reviews. My scheme for a user is:
var User = new mongoose.Schema({
firstName: { type: String, required: true, unique: true },
lastName: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true}
isGuide: Boolean,
rating: {type: Number, "default": 0, min: 0, max: 5},
reviews: [reviewSchema]
});
var Review = new mongoose.Schema({
userId: {type: Schema.ObjectId, ref: 'User'},
author: {type: String, required: true},//contatenation of firstName and lastName of user that wrote review
rating: {type: Number, required: true, min: 0, max: 5},
reviewText: {type: String, required: true},
createdOn: {type: Date, "default": Date.now}
});
mongoose.model('User', User);
I want to be able to:
1/ show a guide and all that guide's reviews
2/ show all a user's reviews
3/ show all guides a user has reviewed
I think my schema above is fine for 1. But is it suitable for 2 and 3? Am I understanding the MonboDB philosophy correctly?

Related

Mongoose Nested Schema - required fields inside array field

I have following mongoose schema -
const UserSchema = new mongoose.Schema({
name: {type: String, required: true, trim: true},
email: {type: String, required: true, trim: true},
password: {type: String, required: true, trim: true},
addresses: [{
type: {type: String, required: true, trim: true},
pinCode: {type: String, required: true, trim: true},
city: {type: String, required: true, trim: true},
state: {type: String, required: true, trim: true},
landmark: {type: String, required: false, trim: true},
}]
})
only name, email and password are required for registration. User can have more than one address , and each address has some required fields like in flipkart.com/account/addresses user's account page.
Each address will be stored in addresses array field in mongodb database.
I want to keep addresses array [ ] when user register. address are only provided through user's account page web page.
But I am getting ValidatorError because schema of doc inside addresses array having required fields.
when user register -
{
name: 'rahul',
email: 'rahul#example.com',
password: 'pass123',
addresses: []
}
user is already registered, and then add address
{
name: 'rahul',
email: 'rahul#example.com',
password: 'pass123',
addresses: [
{
type: 'home',
pinCode: '111222',
city: 'city1',
state: 'state1'
},
{
type: 'work',
pinCode: '333444',
city: 'city2',
state: 'state2',
landmark: 'landmark2'
}
]
}
How to achieve above ??
Any help would be appreciated.
You just have to remove required:true field from address array not even required:false.
Just type and trim will the job and required is false by default so you dont have to include it.
I was doing this -
const userDoc = new UserModel({
name: nm,
email: em,
password: pass,
addresses: []
})
Not passing addresses: [], prevent error ValidatorError
const userDoc = new UserModel({
name: nm,
email: em,
password: pass
})
Try the below code. Hope this will help you.
const ToySchema = new mongoose.Schema({ name: String });
const ToyBoxSchema = new mongoose.Schema({
toys: [ToySchema],
bucketName: String,
numToys: Number
});
const ToyBox = mongoose.model('ToyBox', ToyBoxSchema);
var toyBoxData = {
toys : [
{ name : "Dummy Toy 1"},
{ name : "Dummy Toy 2"},
{ name : "Dummy Toy 3"},
],
bucketName: "My Toy Bucket",
numToys: 3
}
var toyBucket = new ToyBox(toyBoxData);
toyBucket.save( (err: any)=> {
console.log(err);
})
And when you will run the above code, you will be able to see a collection and document like this in your DB, as in the below screenshot.
Hope this will help you. For more information please visit this mongoose documentation link.

I need to fetch data and make an API from a pre existing schema in mongoDB

I need to fetch data and make an API from a pre existing schema in mongoDB, using mongoose to update the total no. of orders in my dashboard..do I just have to import the schema page to my api page? Or what..? .I am new at coding..help would be much appreciated.
enter code here
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let orderPlaced = new Schema({
userID: {type: Schema.Types.ObjectId, required: true, default:null},
shortOrderID: {type: String, required: false, default:null},
sellerID:{type: Schema.Types.ObjectId},
product: [{
productID:{type: Schema.Types.ObjectId, required: true, default:null},
variantID:{type: Schema.Types.ObjectId, required: true, default:null},
inventoryID:{type: Schema.Types.ObjectId, required: true, default:null},
quantity:{type: Number, required: true, default:0},
sellerID:{type: Schema.Types.ObjectId, required: true, default:null},
}],
discount : {type: Number, required: false, default: 0},
totalAmount: {type: Number, required: false, default: 0},
tipAmount: {type: Number, required: false, default: 0},
tax : {type:Number,required : false,default : 0},
deliveryCharges : {type : Number,required : false,default : 0},
paidAmount : {type:Number,required : false,default : 0},
specialInstruction:{type: String, required: false, default: null},
addressID: {type: Schema.Types.ObjectId, required: false, default: null},
paymentID: {type: Schema.Types.ObjectId, required: false, default: null},
status: {type: String, required: false, default: "INCOMPLETE",},
paymentSuccess: {type: Boolean, required: false, default: false},
shippingAssignment: {type: Schema.Types.ObjectId, required: false, default: null},
contactNumber: {type: String, required: false, default: null},
tenantId: {type: String, required: true, default: "self"},
applicationId: {type: String, required: true, default: 'self'},
}, {
timestamps: true
});
This is the scheme from where I have to fetch order placed data and add to my other restapi..how would I do that?

What should I fill in for not so urgent field in db?

I have a db schema which requires linkedin url of the people signing up. I dont want them to fill the linkedin id on signup itself, they are free to add it at dashboard. Below given is the code for the model
const master = mongoose.model('master', new mongoose.Schema({
firstName: {type: String, required: true, unique: false},
lastName: {type: String, required: true, unique: false},
email: {type: String, required: true, unique: true },
linkedinUrl: {type: String, required: false, unique: false },
password: {type: String, required: true, unique: false}
},{strict: true}))
When I leave the field empty more than once, the db returns me an error
error: "{"driver":true,"name":"MongoError","index":0,"code":11000,"errmsg":"E11000 duplicate key error collection: maindb.mentors index: linkedinUrl_1 dup key: { : \"\" }"}"
I realise that having multiple null value is an issue. What other value can I use to mask the empty field? Thank you

MongoDB: How to find the relationships between collections in database

I have a collection of user which has id, firstName, lastName. id field of user collection has been used in another collection.
Is there any way to find all collection which used user id?
user schema:
let userSchema = new mongoose.Schema({
firstName: {
type: String,
trim: true,
required: true
},
lastName: {
type: String,
trim: true,
required: true
}
},
{
timestamps: true,
usePushEach: true
});
training schema:
var trainingSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
name: {type: String, required: true},
institution: {
instituteName: {type: String, required: true},
type: {type: String, required: true},
address: {
country: String,
state: String,
city: String
}
},
startDate: Date,
endDate: Date,
achievements: String,
createdAt: Date,
updatedAt: Date,
endorsers: [{
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
profilePic: {
container: {type: String,default: null},
name: { type: String, default: null }
},
currentPosition: {type: String,default: ""},
currentWorkingCompany: {type: String,default: ""}
}],
});
In above schema userId come from user collection
Note: similar to this which is available in MYSQL:
SELECT
ke.referenced_table_name 'parent table',
ke.referenced_column_name 'parent column',
ke.table_name 'child table',
ke.column_name 'child column',
ke.constraint_name
FROM
information_schema.KEY_COLUMN_USAGE ke
WHERE
ke.referenced_table_name IS NOT NULL
AND table_schema = 'your_db_name'
ORDER BY ke.referenced_table_name;
Source: here
You probably need MySQL function named join. In MongoDB it is named $lookup and it is part of aggregate function.

Mongoose delete nested subdocuments and documents

I have:
let userSchema = mongoose.Schema({
email: {type: String, required: true, unique: true},
passwordHash: {type: String, required: true},
fullName: {type: String, required: true},
salt: {type: String, required: true},
ads: [{type: ObjectId, ref: 'Ad'}],
roles: [{type: String}]
}
let adSchema = mongoose.Schema({
author: {type: ObjectId, ref: 'User'},
title: {type: String, required: true},
category: {type: ObjectId, ref: 'Category', required: true},
town: {type: ObjectId, ref: 'Town', required: true},
}
);
let categorySchema = mongoose.Schema({
name: {type: String, required: true, unique: true},
ads: [{type: ObjectId, ref: 'Ad'}]
}
);
let townSchema = mongoose.Schema({
name: {type: String, required: true, unique: true},
ads: [{type: ObjectId, ref: 'Ad'}]
}
);
I want to find for example town by id and remove all ads in it(and ofcourse to remove the ads from their categories and authors).How can i do that?
I would suggest bulk getting the array of object Ids and using it like this:
Ad.remove({_id: {$in: Ad_ids_array}}, function(){...}); // and so on
You can add a pre-remove hook in the ad schema definition like this:
adSchema.pre('remove', function(next) {
let lethis = this;
// Pull ad out of all the Category docs that reference the removed ad.
this.model('Category').update({}, { $pull: {ads: lethis._id}}, { safe: true }, next);
// Pull ad out of all the User docs that reference the removed ad.
this.model('User').update({}, { $pull: {ads: lethis._id}}, { safe: true }, next);
});
This will remove the ad from the categories and users that have it in their ads array.