Best way to check category owner - node.js

Task model
const TaskSchema = new Schema({
userId: {
type: Schema.Types.ObjectId,
ref: 'User'
},
title: {
type: Schema.Types.String,
required: true
},
description: Schema.Types.String,
createdDate: {
type: Schema.Types.Date,
default: Date.now()
},
position: {
type: Schema.Types.Number,
default: 0
},
categoryId: [{
type: Schema.Types.ObjectId,
ref: 'Category'
}]
});
Category model
const CategorySchema = new Schema({
title: {
type: Schema.Types.String,
required: true
},
description: {
type: Schema.Types.String,
},
categoryThumbnail: {
type: Schema.Types.String,
default: ''
},
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
createdDate: {
type: Schema.Types.Date,
default: Date.now()
}
});
When creating a task, the user can assign a category. Do I need to check the category owner before adding the task to Mongodb. If so, what is the best way to do this? Options:
1. Make a request to the database for all categories and check the user id.
2. Store the category id in the user document and, upon receipt of the request, check this list.

So if the User can create multiple categories and each category is only accessible by the User who created it you have a one-to-many association. In this situation it seems your Option 1 is what you want. Keep the user id on the category and then query all categories that have the user id you're looking for.
Edit:
If possible, I would recommend that you limit the categories the user sees when creating a task to only be categories created by that user. If that is not possible, then you could do one query to grab all the categories from the list of category IDs sent to the server and loop through the results checking if the user IDs are the same.
Category.find({
'id': { $in: [
mongoose.Types.ObjectId('4ed3ede8844f0f351100000c'),
mongoose.Types.ObjectId('4ed3f117a844e0471100000d'),
mongoose.Types.ObjectId('4ed3f18132f50c491100000e')
]}
}, function(err, docs){
docs.forEach(item => {
return item.userId === userId; //compare to userId that sent the request
}
});

Related

Mongoose's populate() does not return data from database

I have the following Schema, and Base is the one-for-all collector of info:
const BaseSchema = mongoose.Schema({
creatorId: { type: mongoose.Schema.Types.ObjectId, required: true },
title: { type: String, required: true },
created: { type: Date, default: Date.now() },
users: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
messages: [{ type: mongoose.Schema.Types.ObjectId, ref: "Message" }]
});
And:
const BaseUserSchema = mongoose.Schema({
userId: { type: String },
baseId: { type: mongoose.Schema.Types.ObjectId },
created: { type: Date, default: Date.now() },
acceptedMembership: { type: Boolean, default: false },
isCreator: { type: Boolean, default: false }
});
(I have one for Message which looks about the same)
The latter one is referred to as User in const User = mongoose.model("User", UserSchema);
When I create a new Base I automatically add a user to a list within. In the DB i can see that the user does exist, but when I call the following the field does not populate:
Base.find({ creatorId: req.params.id })
.populate("users", "messages")
.exec()
.then(data => console.log(data));
I get the following from the console.log:
[ { created: 2018-09-05T03:41:45.416Z,
users: [],
messages: [],
_id: 5b8f508b2760c5329c13a9be,
creatorId: 5b86f7970cd98b2004969bf0,
title: 'testBase1',
__v: 1 } ]
When I first create the base via React front-end, and the base gets added to a list, I see that the users.length is 1, or the length of the automatically created user. When I refresh the page, however, the userlist is empty in the console.
Adding:
Forget to show how I populate the userlist upon creation:
router.post("/add", jwtAuth, (req, res) => {
Base.create({
creatorId: req.body.userId,
title: req.body.title
}).then(baseInfo => {
BaseUser.create({
userId: req.body.username,
baseId: baseInfo._id,
created: Date.now(),
acceptedMembership: true,
isCreator: true
})
.then(baseuser => {
baseInfo.users.push(baseuser);
return baseInfo.save();
})
.then(base => res.json(base.serialize()));
});
});
Answer:
.populate("users", "messages")
to begin with will return messages from users. It has to be two separate entries, like so:
.populate("users")
.populate("messages")
Then, in the model
users: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
refers to the wrong ref. It has to be
users: [{ type: mongoose.Schema.Types.ObjectId, ref: "BaseUser" }],
from
const BaseUser = mongoose.model("BaseUser", BaseUserSchema);
At last, I am not sure if this is needed, but I added a ref to each of the to-be-populated items:
baseId: { type: mongoose.Schema.Types.ObjectId, required: true, ref: "Base" },
baseId: { type: mongoose.Schema.Types.ObjectId, ref: "Base" },
Now it works like a charm, all without additional fetch

Is it possible to populate a field in mongoose which has other information on it too?

This is the relevant portion of my Schema:
var classroomSchema = mongoose.Schema({
students: [{
_id: mongoose.Schema.Types.ObjectId,
ref: 'User',
rate: {
type: Number,
default: 200,
},
referrals: [mongoose.Schema.Types.ObjectId],
}],
)};
Here rate and referrals are properties of the students which are valid in the context of that classroom, and cannot be populated from the Students model.
Is there any way to define my schema such that I can keep those fields(rate and referrals) and also use populate to link other fields such as name, age, etc of the student?
Change your schema to this:
var classroomSchema = mongoose.Schema({
students: [{
rate: { type: Number, default: 200 },
user: { ref: 'User', type: Schema.Types.ObjectId },
referrals: [mongoose.Schema.Types.ObjectId],
}],
});
Usage:
classroom
.findOne(...)
.populate('user')
.exec((err, classroom) => {
let student0 = classroom.students[0];
// student0.rate
// student0.user.name
});

Role-Based login in nodejs and mongoose

I have an application with 2 roles, a User and a Photographer. the difference between these 2 models is a isAdmin field in User and a Photo[ ] in Photographer and a order[ ] in User. But I need only one login for both of them! Clearly, need different views and routs for them! how can I do this? If any guide, I would be appreciated! Thanks a lot!
The schemas are as below:
var userSchema = new Schema({
//some other fields, the same with photographer
isAdmin: { type: Boolean, default: false },
orders: [{
price: { type: Number, default: 0 }
},
{timestamps: true}
]
});
var photographerSchema = new Schema({
//some other fields, the same with user
photos: [{
title: { type: String, default: '' },
path: { type: String },
price: { type: Number, default: 0 },
isAppoved: { type: Boolean, default: false },
},
{timestamps: true}
]
});
You should rethink your architecture. Better solution would be to have 1 User model and 2 profile submodels. User model would contain the type of the user and fetch profile info(writer_profile/user_profile) from the submodels.
If you won't refactor, this will turn in to a mess pretty fast. Think about it, what happens when a User and a Writer registers with the same credentials? You will need to check that too.

Mongoose display with relationships

I have three tables 'cases', 'partners' and 'casepartners' with the following structure:
cases: id,subject,description
partners: id,name,address
casepartners:case,partner,createdAt
I would like to list all cases by also showing for each case, casepartners records where the case id is the same.
I am using this code:
Case.find().sort('-created').exec(function (err, cases) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(cases);
}
});
It shows all cases fine, but I would like to also show for each case object a list of casepartners for that case id...
Let's say a few partners got subscribed to the same case and I would like to list all of those partners or just count how many partners got subscribed to that case.
I am using Angularjs to list all cases using the ng-repeat but I am kinda confused if I have to make a separate call to show casepartners records for each case within ng-repeat or attach this in the same function by using some kind of .populate() or something else with the entity relationships.
These are the models defined:
var CaseSchema = new Schema({
subject: {
type: String,
default: '',
trim: true,
required: 'Subject cannot be blank'
},
description: {
type: String,
default: '',
trim: true
},
created: {
type: Date,
default: Date.now
},
customer: {
type: Schema.ObjectId,
ref: 'Customer'
},
category: {
type: Schema.ObjectId,
ref: 'Category'
}
});
var CasePartnerSchema = new Schema({
case: {
type: Schema.ObjectId,
ref: 'Case'
},
partner: {
type: Schema.ObjectId,
ref: 'Partner'
},
created: {
type: Date,
default: Date.now
}
});
var PartnerSchema = new Schema({
name: {
type: String,
trim: true,
default: ''
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
Can anyone help with this?
If possible I would recommend redefining your collections (tables) since having a CasePartner collection is a little redundant.
Instead of having a case and casePartner collection, I would recommend you only have a case collection and then have an array of partners inside of that collection.
Your schema would then look like this:
var CaseSchema = new Schema({
partners: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Partner'
}],
subject: {
type: String,
default: '',
trim: true,
required: 'Subject cannot be blank'
},
description: {
type: String,
default: '',
trim: true
},
created: {
type: Date,
default: Date.now
},
customer: {
type: Schema.ObjectId,
ref: 'Customer'
},
category: {
type: Schema.ObjectId,
ref: 'Category'
}
});
Your find would then look like this:
Case
.find({})
.sort('-created')
//.populate() populates all info from the partnersSchema for each partner
.populate('partners')
.exec(function(err, cases) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(cases);
}
});
Check out this for more on MongoDB schema design.
try mongoose-reverse-populate. There is a way called populate in mongoose but that helps you when you are first searching caseparters and populate case types . however what you wanted is kind of reverse of that .

How filter sub sub document in MongoDB

Hello I am working with the full Stack 'MEAN' and i have a data structure in MongoDB as indicated below:
var ExpenseSchema = new Schema({
date: {
type: Date,
default: Date.now,
required: 'Ingrese la fecha del comprobante'
},
supplier: {
type: Schema.ObjectId,
ref: 'Supplier',
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
var SupplierSchema = new Schema({
name: {
type: String,
default: '',
required: 'Ingrese la Razon Social del Proveedor',
trim: true
},
category: {
type: Schema.ObjectId,
ref: 'Category',
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
var CategorycompraSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Rubrocompra name',
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
Each 'Expense' has a 'Supplier' and each supplier has a 'Category'
I need to query so that I filter all 'Expenses' in a particular category. Someone could tell me how this can be done with MongoDB or mongoose?
That is an important case in mongodb, aggregations in mongodb is the right approach to solve this. You need to $unwind the supplier array and then category array and then use $group to put it back together:
My solution may differ depending upon your requirement, but this is something you have to do:
db.test.aggregate(
{ $match: {...}}, //match query
{ $unwind: '$supplier'},
{ $unwind: '$supplier.category'},
{ $match: {supplier.category.a: ...}}, //match query after unwinding of supplier and category
{ $group: {_id: '$_id', ...})
It will first unwind the supplier array and then unwind category array
But since you are also using mongoose, you can use plain JavaScript. You can fetch all expenses and then loop through them and
obtain your result
Expense.find().then(function(expenses) {
expenses.forEach(function(suppliers){
suppliers.forEach
...
})
})
Although this javascript way would increase effort in single threaded enviroment(node js), but still it comes in handy for some typical mongodb queries

Resources