Mongoose Ref User Object - node.js

I hope everyone learning something today. I need some help. I have a Gift model which looks something like this:
let giftSchema = new mongoose.Schema({
gift: String,
date: {
type: Date
},
giftDescription: String,
giftAmount: String,
giftCode: String,
redeemCode: String,
passCode: String,
senderFirstName: String,
senderLastName: String,
giftMessage: String,
user: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
username: String
}
});
module.exports = mongoose.model('Gift', giftSchema);
This is my user model:
const mongoose = require('mongoose'),
passportLocalMongoose = require('passport-local-mongoose');
let UserSchema = new mongoose.Schema({
firstName: String,
lastName: String,
alaisFirstName: String,
alaisLastName: String,
username: String,
password: String,
isAdmin: Boolean,
addressLine1: String,
addressLine2: String,
city: String,
state: String,
zipCode: String
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', UserSchema);
I have pretty much 2 users, and no guest. The admin sends gifts to a user. So as an admin, on the new route, I need to send something to the user. However, in my field: for ( think gmail search field ) I will be searching for either firstName, lastName, alaisFirstName, and alaisLastName than sending the gift to the user.
How could I model that? I cant do it by type: mongoose.Schema.Types.ObjectId, because the admin is the one sending it to the user, but I want something similar to that.

Related

How to find documents in mongoose by populate field?

I have an issue with mongoose. When I make some field referenced to other collection, I lose ability to search by this field. I don't know how to describe my problem correctly, so look at the examples please.
Schema:
var PostSchema = new Schema({
title: String,
content: String,
url: String,
author: { type: Schema.ObjectId, ref: 'User'},
mainImage: String,
type: String
});
Query:
Post.find({author: user._id})
.then(posts => res.send(posts))
.catch(err => res.status(500).send(err))
Returns nothing. But if I change "author" field to String, it will works, but without populate. :(
Upd:
I can't believe. I made this:
var PostSchema = new Schema({
title: String,
content: String,
url: String,
author: {type: String, ref: 'User'},
mainImage: String,
type: String
});
Just change type to string. Omg I can't figure out how it working. How mongoose knows which field I need to compare in ref collection? I mean there is no direct link to "_id" field (see query). Can someone explain?
Upd2:
Auhtor schema:
var UserSchema = new Schema({
id: String,
about: String,
firstname: String,
lastname: String,
email: String,
avatar: String,
city: String,
country: String,
dateOfBirth: String,
password: String,
},
{
timestamps: true
})
As you can see, I using additional "id" field just in purpose to give users simple numeric id for url (/id1 etc). But I am sure this isn't the source of the problem :)
Try change the type: Schema.ObjectId to type: mongoose.Schema.Types.ObjectId

Creating different types of users in mongodb

I want to create an API to register, login and other things. two types of users
A teacher and a student , I'm using MongoDb and defining the schema.
const UserSchema = new Schema({
studentInfo : {
name: String,
email: String,
password: String,
birthday: Date,
state: String,
zip_code: String,
address: String,
phone_number: String,
},
teacherInfo : {
name: String,
email: String,
password: String,
birthday: Date,
state: String,
zip_code: String,
address: String,
phone_number: String,
course: {
title: String,
price: Number,
description: String
}
},
role: String
});
is this a good approach? or there is a better way?
I added the role field to perform route guarding on the front end.
I'm using Nodejs and Express.
any help will be much appreciated, thank you.
This is one way of embedding both student and teacher object in the same document and you can simply get data with single query. Although you don't need to separately embed the common fields in object like name, email, password, phone_number etc. teacherInfo would be like this
teacherInfo : {
course: {
title: String,
price: Number,
description: String
}
}
You can create different schemas for student and teacher (as they are unique and you might need them independent sometimes), and make User as the base model.
var User= new Schema({
name: String,
email: String,
password:String,
birthday: Date,
state: String,
zip_code: String,
address: String,
phone_number: String,
_teacher:{type:Schema.Types.ObjectId, ref:'Teacher'},
_student: {type:Schema.Types.ObjectId, ref:'Student'}
});
If _teacher has a value then the user can be considered as a teacher.
If _student has a value then the user can be considered as a student.
//Teacher Model
var Teacher = new Schema({
course: {
title: String,
price: Number,
description: String
},
//other teacher's fields
})
//Student Schema
var Student= new Schema({
//student's fields if you need in future
})

Mongoose Nested Populate Not Working

So I am currently extremely confused when it comes to mongoose populating.
My data structure is as follows: User has an array of Clients, a Client has an array of loans. I am using User.find and populating the client, no problem. But then how do I populate the loans that is inside of the client? I have tried this:
Basically, the goal is to pass in an array of Clients, each client will contain a loan. But for now, I want that loan object to be empty. The Client is being populated correctly, however, the Loan reference is being passed as undefined.
app.get("/loans", IsLoggedIn, function(req, res) {
User.findById(req.user._id).populate({path: "clients", populate: { path: "loans", model: "loan"}}).exec(function(err, user){
if(err){
console.log(err);
} else{
var amountRepaid = calcRepaid(user.clients.loans);
console.log(user.clients.loans);
res.render("index", {clients: user.clients, amountRepaid: amountRepaid});
}
});
However it doesn't seem to work, my models are listed below and any help is appreciated!
models:
Client:
var mongoose = require("mongoose");
var clientSchema = mongoose.Schema({
loans: [{
type: mongoose.Schema.Types.ObjectId,
ref: "loan"
}],
emailAdderess: String,
firstname: String,
lastname: String,
contactNumber: String ,
dateCreated: {type: Date, default: Date.now},
gender: String,
})
module.exports = mongoose.model("Client", clientSchema);
User:
const mongoose = require("mongoose");
const passportLocalMongoose = require("passport-local-mongoose");
var UserSchema = mongoose.Schema({
username: String,
password: String,
firstname: String,
lastname: String,
clients: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Client"
}]
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
Loan:
var mongoose = require("mongoose");
var LoanSchema = mongoose.Schema({
firstName: String,
lastName: String,
email: String,
contactNumber: Number,
amountBorrowed: Number,
length: String,
address: String,
dateDue: Date,
gender: String,
date: { type: Date, default: Date.now },
amountRepaid: { type: Number, default: 0},
loanRepaid: {type: Boolean, default: false}
})
module.exports = mongoose.model("loan", LoanSchema);
Try this:
.populate({
path: 'clients',
populate: {
path: 'clients.loans'
}
})

MongoDB trouble, is both way references a thing?

So I have a website built with node.js + mongoDB (mongoose). I'm having a bit trouble in the design of the database.
I want to have 2 logins, one for institutions and another for professionals. Do I need to double reference them (like the professional has a ref to Inst and an institution has a ref to the professional)?
For instance, If I want to display the list of all professionals when I login with an institution is trivial but if I don't ref the institution on the User (professional) is not so simple. So which one is better? Having code to find the user in every institution and get its institution name or both referencing each other and then do a populate?
If I pick both referencing each other, is there some way to guarantee that both of them will always be linked and having no broken only one way references?
Code:
var userSchema = new mongoose.Schema({
username: String,
password: String,
email: String,
name: String,
created_at: {type: Date, default: Date.now},
status : Boolean,
institution: { type:mongoose.Schema.ObjectId, ref:'Inst' }
});
mongoose.model('User', userSchema);
var User = mongoose.model('User');
var instSchema = new mongoose.Schema(
{
name : String,
professional : [{ type:mongoose.Schema.ObjectId, ref:'User'}]
});
mongoose.model('Inst', instSchema);
var Inst = mongoose.model('Inst');
How about just merge instSchema into userSchema as below, with additional user_type to indicate which type this user belong to, Professional or Institutions. Also one new related_user to store the other related User documents
var userSchema = new mongoose.Schema({
username: String,
password: String,
email: String,
name: String,
created_at: {type: Date, default: Date.now},
status : Boolean,
user_type: {type: String, enum: ['Prof', 'Inst']},
related_user: [{ type:mongoose.Schema.ObjectId, ref:'User'}]
});
mongoose.model('User', userSchema);
var User = mongoose.model('User');

How to reference another schema in my Mongoose schema?

I'm building a Mongoose schema for a dating app.
I want each person document to contain a reference to all the events they've been to, where events is another schema with its own models in the system. How can I describe this in the schema?
var personSchema = mongoose.Schema({
firstname: String,
lastname: String,
email: String,
gender: {type: String, enum: ["Male", "Female"]}
dob: Date,
city: String,
interests: [interestsSchema],
eventsAttended: ???
});
You can do so by using Population
Population is the process of automatically replacing the specified
paths in the document with document(s) from other collection(s). We
may populate a single document, multiple documents, plain object,
multiple plain objects, or all objects returned from a query.
Suppose your Event Schema is defined as follows:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var eventSchema = Schema({
title : String,
location : String,
startDate : Date,
endDate : Date
});
var personSchema = Schema({
firstname: String,
lastname: String,
email: String,
gender: {type: String, enum: ["Male", "Female"]}
dob: Date,
city: String,
interests: [interestsSchema],
eventsAttended: [{ type: Schema.Types.ObjectId, ref: 'Event' }]
});
var Event = mongoose.model('Event', eventSchema);
var Person = mongoose.model('Person', personSchema);
To show how populate is used, first create a person object,
aaron = new Person({firstname: 'Aaron'})
and an event object,
event1 = new Event({title: 'Hackathon', location: 'foo'}):
aaron.eventsAttended.push(event1);
aaron.save(callback);
Then, when you make your query, you can populate references like this:
Person
.findOne({ firstname: 'Aaron' })
.populate('eventsAttended') // only works if we pushed refs to person.eventsAttended
.exec(function(err, person) {
if (err) return handleError(err);
console.log(person);
});
To reference the ObjectId of one table in another table refer below code
const mongoose = require('mongoose'),
Schema=mongoose.Schema;
const otpSchema = new mongoose.Schema({
otpNumber:{
type: String,
required: true,
minlength: 6,
maxlength: 6
},
user:{
type: Schema.Types.ObjectId,
ref: 'User'
}
});
const Otp = mongoose.model('Otp',otpSchema);
// Joi Schema For Otp
function validateOtp(otp) {
const schema = Joi.object({
otpNumber: Joi.string().max(6).required(),
userId: Joi.objectId(), // to validate objectId we used 'joi-objectid' npm package
motive: Joi.string().required(),
isUsed: Joi.boolean().required(),
expiresAt: Joi.Date().required()
});
// async validate function for otp
return schema.validateAsync(otp);
}
exports.Otp = Otp;
exports.validateOtp = validateOtp;
List item
var personSchema = mongoose.Schema({
firstname: String,
lastname: String,
email: String,
gender: {
type: String,
enum: ["Male", "Female"]
}
dob: Date,
city: String,
interests: [interestsSchema],
eventsAttended[{
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Place"
}],
**//ref:"Places"...you have put the other model name**
*OR*
eventsAttended[{
type: mongoose.Types.ObjectId,
required: true,
ref: "Place"
}],
});

Resources