Is it possible to reference two schemas to eachother in Mongoose? - javascript

I have two Schemas, and I want to be able to access both of them from the other one.. I am trying to do something like this:
//email.js
var mongoose = require('mongoose')
,Schema = mongoose.Schema
, FoodItemSchema = require('../models/fooditem.js')
, UserSchema = require('../models/user.js').schema
, User = require('../models/user.js').model
console.log(require('../models/user.js'));
var emailSchema = new Schema({
From : String,
Subject : FoodItemSchema,
Body : String,
Date: Date,
FoodItems : [FoodItemSchema],
Owner : { type : Schema.Types.ObjectId , ref: "User" }
});
module.exports = {
model: mongoose.model('Email', emailSchema),
schema : emailSchema
}
//user.js
var mongoose = require('mongoose')
,Schema = mongoose.Schema
, Email = require('../models/email.js').model
, EmailSchema = require('../models/email.js').schema
console.log(require('../models/email.js'));
var userSchema = new Schema({
googleID : String,
accessToken : String,
email : String,
openId: Number,
phoneNumber: String,
SentEmails : [EmailSchema]
// Logs : [{type: Schema.ObjectId, ref: 'events'}]
});
module.exports = {
model : mongoose.model('User', userSchema),
schema : userSchema
}
The first console.log() prints empty string and the second one prints as expected. I feel like I am trying to get the variables in the other schema even before they were created. Is there a common workaround for this? Or should I avoid double dependencies in my design?

Yes, you can create cross-references in Mongoose. But there is no way to create cyclic dependencies in Node.js. Though, you don't need to, because there is no need to require user schema in order to create a reference:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
, FoodItemSchema = require('../models/fooditem.js');
var emailSchema = new Schema({
From: String,
Subject: FoodItemSchema,
Body: String,
Date: Date,
FoodItems: [FoodItemSchema],
Owner: { type: Schema.Types.ObjectId , ref: 'User' }
});
module.exports = {
model: mongoose.model('Email', emailSchema),
schema: emailSchema
}

You can define Schema Add statements to describe common attributes:
var mongoose = require('mongoose')
, Schema = mongoose.Schema;
module.exports = exports = function productCodePlugin(schema, options) {
schema.add({productCode:{
productCode : {type : String},
description : {type : String},
allowed : {type : Boolean}
}});
};
then require the add statement into multiple schema definition files.
var mongoose = require('mongoose')
, Schema = mongoose.Schema
, ObjectId = Schema.ObjectId
, productCodePlugin = require('./productCodePlugin');
var ProductCodeSchema = new Schema({
});
ProductCodeSchema.plugin(productCodePlugin);

Related

How do i reference 1 Mongoose Schema inside another as its property?

I am trying to make a store app and have created two mongoose schemas. Order.js and Product.js, I want to reference the product schema as a property of the order schema.
Order.js
const mongoose = require('mongoose');
const Product=require('../models/product.js');
const orderSchema = new mongoose.Schema(
{
date: {
type:Date,
default: Date.now},
customerName: String,
customerAddress: String,
creditCard: Number,
products:[] //product model
},
{ timestamps: true }
);
product.js
const mongoose = require('mongoose');
const productSchema = new mongoose.Schema(
{
name: String,
price: Number,
category: String
},
{ timestamps: true }
);
const Product = mongoose.model('Product', productSchema);
module.exports= Product;
This is my approach when it comes to nested schemas in mongoose :
first you have to create an object of your Product schema , to avoid duplicating your Product model , you can create an object :
product
with your fields , then create your Product schema by simply const Product = new Schema(product); , then you can import the product object here in your order.js and declare your schema as follows :
import product;
const Order = new Schema({
......
......
order : {
type : product ,
......
}
})

saving array type value inside mongodb schema using node js

I am trying to put array data inside my schema but its not showing in my mongodb Schema
ownerSchema.js
var ownerSchema = Schema({
ownerId : String,
fname : String,
lname : String,
shopPlace : {
type: Schema.Types.ObjectId,
ref: 'Shop'
},
shopType String
});
var Owner = mongoose.model('Owner', ownerSchema);
shopSchema.js
var shopSchema = Schema({
_id : String,
shopName : String,
location : String,
startDate : Date,
endDate : Date
});
var Shop = mongoose.model('Shop', shopSchema);
as I am sending array format data inside shopType but its not showing any data inside schema
as I am sending this from postman my format look like this
{
"ownerId" : "Own001",
"fname" : "Tom",
"lname" : "jerry",
"shopPlace" : {
"shopName" : "Juice Center",
"location" : "Mumbai",
},
"shopType" : ["Juice","vegetables"]
}
but when I am sending this data only ownerId, fname,lname, shopPlace showing inside schema my shopType data can't be seen
const addTask = async (req, res) => {
const { shopName, location } = req.body.shopPlace;
const shopDetails = new Shop({
shopName,
location,
});
await shopDetails.save();
const { ownerId, fname, lname, shopType } = req.body;
const ownerDetail = new Owner({
ownerId,
fname,
lname,
shopType,
shopPlace: shopDetail._id,
});
await shopDetail.save();
};
I want to store shopType in array format but Its even not showing inside my schema
change your schema like it
var ownerSchema = Schema({
ownerId : String,
fname : String,
lname : String,
shopPlace : {
type: Schema.Types.ObjectId,
ref: 'Shop'
},
shopType : [{
type: String
}]
});
var Owner = mongoose.model('Owner', ownerSchema);

Manage authentication of different types of users in express.js using passport.js

I am having problem managing the states of different types of users using Passport.js in Express.js 4.x.
I have 3 kinds user collections in my mongodb database
1. Member (has his own profile page)
2. Operator (has his own dashboard)
3. Admin (handles the backend)
I have created their separate Login/Registration systems. But only member seems to work, and the others don't. I have even written different sets of login/registration strategies for each user.
Like for the member passport.use('signup') and passport.use('login').
for operator passport.use('op-signup') and passport.use('op-login') and so on.
What I think is that I am not using the correct approach for handling users, means the collections don't need to be separated but role based in a single collection. Right ?
Here is the current mongoose models I have right now;
// Member Schema
var MemberSchema = new Schema({
username: String,
password: String,
name: { first: String, last: String },
locality: String,
// and other attributes
});
module.exports = mongoose.model('Member', MemberSchema);
// OperatorSchema
var OperatorSchema = new Schema({
username: String,
password: String,
name: { first: String, last: String },
officeAddress: String,
privatePhone: Number,
// and other attributes related to the operator
});
module.exports = mongoose.model('Operator', OperatorSchema);
Is the above approach correct or like this ?
var UserSchema = new Schema({
username: String,
password: String,
roles: {
member: { type: Schema.Types.ObjectId, ref: 'Member' },
operator: { type: Schema.Types.ObjectId, ref: 'Operator' },
admin: { type: Schema.Types.ObjectId, ref: 'Admin' }
}
});
module.exports = mongoose.model('User', UserSchema);
// and then plug the sub models to this parent one
// Member Schema
var MemberSchema = new Schema({
_user: { type: Schema.Types.ObjectId, ref: 'User' },
name: { first: String, last: String },
locality: String,
// and other attributes
});
module.exports = mongoose.model('Member', MemberSchema);
// OperatorSchema
var OperatorSchema = new Schema({
_user: { type: Schema.Types.ObjectId, ref: 'User' },
name: { first: String, last: String },
officeAddress: String,
privatePhone: Number,
// and other attributes related to the operator
});
module.exports = mongoose.model('Operator', OperatorSchema);
I am quite confused here and in a stuck situation, because when a user state is managed in session after login, the user object is exposed to the request object, and so it can only handle one type of user at a time, and may be member, operator and admin can't log in at the same time from the same browser.
So how do I manage all of these user as different instances in the browser ?
I am quite a newbie in Node.js and coming from a PHP background where managing user states was a breeze :)
What i would do is to add plugins, because you are duplicating username and password field, it is very redundant
models/plugins/member.js
module.exports = function(schema) {
schema.add({
// All the appropriate fields that your member schema need
role: String,
});
}
models/user.js
var member = require(./plugins/member);
var UserSchema = mongoose.Schema({
username: String,
password: String
});
UserSchema.plugins(member);
Later on when you want to check which user could access to which route, use middleware to check it
create this in your passport configuration
exports.requireRole = function(role) {
return function(req, res, next) {
if (req.user && req.user.role === role) next();
else
res.send(404);
}
}
In your route later
app.get('/profile', requireRole('member'), function(req, res) {
// do whatever you want to do
});
app.get('/dashbord', requireRole('operator'), function(req, res) {
// do whatever you want to do
});
There are a lot of ways to implement different access level to a user. This method is one of many.
The best solution would be to use schema inhertiance. That is why we use an ORM like mongoose.
var VehicleSchema = mongoose.Schema({
make : String,
}, { collection : 'vehicles', discriminatorKey : '_type' });
var CarSchema = VehicleSchema.extend({
year : Number
});
var BusSchema = VehicleSchema.extend({
route : Number
})
var Vehicle = mongoose.model('vehicle', VehicleSchema),
Car = mongoose.model('car', CarSchema),
Bus = mongoose.model('bus', BusSchema);
var accord = new Car({
make : 'Honda',
year : 1999
});
var muni = new Bus({
make : 'Neoplan',
route : 33
});
accord.save(function(err) {
muni.save(function(err) {
// vehicles are saved with the _type key set to 'car' and 'bus'
});
})
At this point in MongoDB you will have documents similar to this
{ "_type" : "car", "make" : "Honda", "year" : 1999, "_id" : ObjectId("5024460368368a3007000002"), "__v" : 0 }
{ "_type" : "bus", "make" : "Neoplan", "route" : 33, "_id" : ObjectId("5024460368368a3007000003"), "__v" : 0 }
Source
when querying
Vehicle.find({}, function(err, vehicles) {
console.log(vehicles[0]); // vehicles[0] instanceof Car === true
console.log(vehicles[1]); // vehicles[1] instanceof Bus === true
});
Checkout source / more examples by looking at briankircho little cheatsheet enter link description here

Linking 2 mongoose schemas

I have two Schemas, a Team and a Match. I want to use the Team Schema to identify the Teams in the Match Schema. So far, here is my Team and Match JS files. I want to link the Team Schema to my Match Schema so that I can identify the home or away team simply, and so that I am storing in the Match Schema an actual Team object.
This way I can refer to the home team for example as Match.Teams.home.name = England (this is just an example of course)
Team.js
'use strict';
var util = require('util');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var validatePresenceOf = function(value){
return value && value.length;
};
var getId = function(){
return new Date().getTime();
};
/**
* The Team schema. we will use timestamp as the unique key for each team
*/
var Team = new Schema({
'key' : {
unique : true,
type : Number,
default: getId
},
'name' : { type : String,
validate : [validatePresenceOf, 'Team name is required'],
index : { unique : true }
}
});
module.exports = mongoose.model('Team', Team);
And here is what I am trying to do with Match.js
'use strict';
var util = require('util');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var TeamSchema = require('mongoose').model('Team');
var validatePresenceOf = function(value){
return value && value.length;
};
var toLower = function(string){
return string.toLowerCase();
};
var getId = function(){
return new Date().getTime();
};
/**
* The Match schema. Use timestamp as the unique key for each Match
*/
var Match = new Schema({
'key' : {
unique : true,
type : Number,
default: getId
},
'hometeam' : TeamSchema,
'awayteam' : TeamSchema
});
module.exports = mongoose.model('Match', Match);
Your solution: Use the actual schema, rather than a model that uses the schema:
module.exports = mongoose.model('Team', Team);
To
module.exports = {
model: mongoose.model('Team', Team),
schema: Team
};
and then var definition = require('path/to/js'); that, and use definition.schema instead of a model directly
You don't want to nest schemas.
Try Population in Mongoose: http://mongoosejs.com/docs/populate.html
That will solve your problem.
Try using Schema.Types.ObjectId in Match.js :
hometeam: { type: Schema.Types.ObjectId, ref: 'Team' }
awayteam: { type: Schema.Types.ObjectId, ref: 'Team' }

Mongoose schema within schema

How can I add a schema to another schema? This doesn't seem to be valid:
var UserSchema = new Schema({
name : String,
app_key : String,
app_secret : String
})
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
user : UserSchema
})
I checked the website and it shows how to declare it for an array but not for single.
Thanks
There are a few ways to do this. The simplest is just this:
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
user : Schema.ObjectId
});
Then you just have to make sure your app is writing that id and using it in queries to fetch "related" data as necessary.
This is fine when searching tasks by user id, but more cumbersome when querying the user by task id:
// Get tasks with user id
Task.find({user: user_id}, function(err, tasks) {...});
// Get user from task id
Task.findById(id, function(err, task) {
User.findById(task.user, function(err, user) {
// do stuff with user
}
}
Another way is to take advantage of Mongoose's populate feature to simplify your queries. To get this, you could do the following:
var UserSchema = new Schema({
name : String,
app_key : String,
app_secret : String,
tasks : [{type: Schema.ObjectId, ref: 'Task'}] // assuming you name your model Task
});
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
user : {type: Schema.ObjectId, ref: 'User'} // assuming you name your model User
});
With this, your query for all users, including arrays of their tasks might be:
User.find({}).populate('tasks').run(function(err, users) {
// do something
});
Of course, this means maintaining the ids in both places. If that bothers you, it may be best to stick to the first method and just get used to writing more complex (but still simple enough) queries.
As of version 4.2.0, mongoose supports single subdocuments.
From the docs:
var childSchema = new Schema({ name: 'string' });
var parentSchema = new Schema({
// Array of subdocuments
children: [childSchema],
// Single nested subdocuments. Caveat: single nested subdocs only work
// in mongoose >= 4.2.0
child: childSchema
});
What about this simple solution?
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
user : {
name : String,
app_key : String,
app_secret : String
}
})

Categories

Resources