Select fields based on permission field - mongodb

Hello guys i am having a problem getting from database only fields that are permitted by the user.
So my schema is:
var profileSchema = mongoose.Schema({
authId: {type: Schema.Types.ObjectId, ref: 'Auth'},
fname: String,
lname: String,
am: Number,
email: String,
location: String,
languages: [String],
birth_date: {
type: Date,
default: Date.now
},
reg_date: {
type: Date,
default: Date.now
},
last_log: {
type: Date,
default: Date.now
},
permissions: {
location: {type: Boolean,Default:true},
birth_date: {type: Boolean,Default:true},
email: {type: Boolean,Default:true},
am: {type: Boolean,Default:true},
subjects: {type: Boolean,Default:true},
files: {type: Boolean,Default:true},
posts: {type: Boolean,Default:true}
},
ip: String,
subjects: [{type: Schema.Types.ObjectId, ref: 'Subject'}],
files: [{type: Schema.Types.ObjectId, ref: 'FileIndex'}],
posts: [{type: Schema.Types.ObjectId, ref: 'Post'}],
notifications: [{type: Schema.Types.ObjectId, ref: 'Notifications'}]
});
And I am trying to get only fields that in permission field have true which means it's permitted. So I am running the following query :
database.Profile.findOne({_id: req.params.id}).exec(function (err, profile) {
console.log(profile);
res.send(profile);
});
How do I select only the fields that are permitted?

Try this, It ,might get you what you want:
database.Profile.findOne({_id: req.params.id},{location:$.permissions.location , birth_date:$.permissions.birth_date, email:$.permissions.email, am:$.permissions.am, subjects:$.permissions.subjects, files:$.permissions.files, posts:$.permissions.posts}).exec(function (err, profile) {
console.log(profile);
res.send(profile);
});

You could do a query with the lean() method chained since documents returned from queries with the lean option enabled are plain javascript objects, not MongooseDocuments and manipulate the object returned by removing the keys as determined by the permissions object fields:
Object.filter = function( obj, predicate) {
var result = {}, key;
for (key in obj) {
if (obj.hasOwnProperty(key) && !predicate(obj[key])) {
result[key] = obj[key];
}
}
return result;
};
database.Profile.findOne({_id: req.params.id}).lean().exec(function (err, doc) {
if (err) return handleError(err);
console.log(doc);
console.log(doc.permissions);
var filtered = Object.filter(doc.permissions,
function (key){ return doc.permissions[key]; }
);
console.log(filtered);
res.send(filtered);
});
Another alternative that uses the Mongoose's projection select() method would be to make two queries; the first one will return the whole document and the next will query the same document but project the fields based on the permissions object fields:
The following shows this:
database.Profile.findOne({_id: req.params.id}).lean().exec(function (err, doc) {
console.log(doc);
console.log(doc.permissions);
var projection = Object.keys(doc.permissions)
.filter(function (key){ return doc.permissions[key]; })
.join(' ');
console.log(projection);
database.Profile.findOne({_id: req.params.id})
.select(projection)
.exec(function (err, profile) {
if (err) return handleError(err);
res.send(profile);
});
});

Related

How to work with many to few mongodb relationship with feathersjs?

I have two models, with a many-to-few relationship, that I'm modelling as follows:
// Portfolio
const portfoliosSchema = new Schema({
name: { type: String, required: true },
description: { type: String },
user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
positions: [{
stock: { type: Schema.Types.ObjectId, ref: 'Stock', required: true },
cost: number,
amount: number,
}]
});
// Stock
const stocksSchema = new Schema({
exchange: { type: String, required: true },
symbol: { type: String, required: true },
company: { type: String },
description: { type: String }
});
Without writing a custom service / in a feathers friendly way, how would I:
Query portfolios and populate the relevant records from the stocks
collection
Simplify insert/updates to the nested positions within the portfolio schema (ie without updating the entire record)
Is this supported / should I write a custom service and/or normalize the relationship?
Edit - Solved #1 the first issue of getting extra data using a before hook:
function(hook) {
const query = hook.params.query;
hook.params.query = Object.assign({},query,{
$populate: {
path: 'positions.stock',
select: 'exchange symbol'
}
});
}
Sample of populate code, adjust to your needs:
Portfolio.find({ some: 'params' })
.populate({ path: 'stock', select: 'name -_id' })
.exec((err, portfolios) => {
res.json({ portfolio: portfolios });
});
Updating a nested array item:
Position.update({ 'position._id': 'h43q9h94945d948jh098j6h0' }, {
'$set': { 'position.$.whatever': 'your-updated-stuff' }
}, err => {
if (err) return console.log(err));
res.json({ success: true });
});

Push ObjectId to nested array in Mongoose

(Basic library CRUD application)
I am trying to create a document containing some global data about a given book, and then within a User document, add the ObjectId of the newly-created book to an array containing all books belonging to that user.
I have three data models in my application:
var userSchema = new mongoose.Schema({
name: String,
password: String,
email: String,
books: [BookInstanceSchema],
shelves: [String]
});
var bookSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
author: {
type: String,
required: true
},
description: String,
pageCount: Number,
ISBN: String,
googleID: String,
thumbnail: String,
publisher: String,
published: String,
});
var BookInstanceSchema = new mongoose.Schema({
bookId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Book'
},
userReview: String,
userRating: {
type: Number,
get: v => Math.round(v),
set: v => Math.round(v),
min: 0,
max: 4,
default: 0
},
shelf: String
});
The User model contains a nested array of BookInstances, which contain user-specific data such as ratings or reviews for a given book. A bookInstance in turn contains a reference to the global data for a book, to avoid duplicating data that isn't specific to any user.
What I'm trying to do is first save the global data for a book (thus generating an _id), and when done, save a bookInstance containing that _id in a given user's array of books:
router.post('/save/:id', function(req, res) {
var url = encodeurl('https://www.googleapis.com/books/v1/volumes/' + req.params.id);
request(url, function(err, response, data) {
parsedData = JSON.parse(data);
var newBook = {
title: parsedData.volumeInfo.title,
author: parsedData.volumeInfo.authors[0],
description: parsedData.volumeInfo.description,
pageCount: parsedData.volumeInfo.pageCount,
ISBN: parsedData.volumeInfo.description,
googleID: parsedData.id,
publisher: parsedData.volumeInfo.publisher,
published: parsedData.volumeInfo.publishedDate,
thumbnail: parsedData.volumeInfo.imageLinks.thumbnail
};
Book.create(newBook, function(err, newBook) {
if (err) {
console.log(err);
}
else {
console.log(newBook._id);
console.log(mongoose.Types.ObjectId.isValid(newbook._id));
User.findByIdAndUpdate(req.session.id, {
$push: {
"books": {
bookId: newBook._id,
userRating: 0,
userReview: ''
}
}
},
{
upsert: true
},
function(err, data){
if(err) {
console.log(err);
}
else {
res.redirect('/');
}
});
}
});
});
});
I'm getting the error:
message: 'Cast to ObjectId failed for value "hjhHy8TcIQ6lOjHRJZ12LPU1B0AySrS0" at path "_id" for model "User"',
name: 'CastError',
stringValue: '"hjhHy8TcIQ6lOjHRJZ12LPU1B0AySrS0"',
kind: 'ObjectId',
value: 'hjhHy8TcIQ6lOjHRJZ12LPU1B0AySrS0',
path: '_id',
reason: undefined,
Every time, the value in the error (in this case, jhHy8T...) is different than the newBook._id I'm attempting to push into the array:
console.log(newBook._id); // 5a120272d4201d4399e465f5
console.log(mongoose.Types.ObjectId.isValid(newBook._id)); // true
It seems to me something is wrong with my User update statement:
User.findByIdAndUpdate(req.session.id, {
$push: {
"books": {
bookId: newBook._id,
userRating: 0,
userReview: ''
}
}...
Any help or suggestions on how to better organize my data are appreciated. Thanks!

null results of search by _id in mongoose

I'm getting [] res in mongoose find by {parentId: cat._id}
var ObjectId = Schema.ObjectId;
var CategorySchema = new Schema({
name: String,
slug: String,
parentId: {type: ObjectId, required: false},
ancestors: {
type: [{
_id: ObjectId,
name: String,
slug: String
}], required: false
}
});
CategorySchema.statics.getNested = function(parentSlug,cb){
this.findOne({slug:parentSlug},function(err,cat){
if (err) {
cb(err);
} else {
this.find({parentId: cat._id},function(err, cats){
console.log(cats);
if (err){
cb(err);
} else {
cb(null,cats);
}
});
}
});
};
I tried {parentId: ObjectId(cat._id)} but this did not work too // ObjectId(cat._id) -> undefined
How do I search mongoose by _id?
UPDATE!
The query
Category.find({parentId:'5634eeb38a33a59c1dffa6ee'}, function(err,res){
console.log(res);
});
is working fine but how?
It should be {parentId: mongoose.Types.ObjectId(cat._id)}
You have incorrect ObjectId type in your schema, you should use Schema.Types.ObjectId instead of Schema.ObjectId because they return different values:
http://mongoosejs.com/docs/api.html#schema-objectid-js
http://mongoosejs.com/docs/api.html#types-objectid-js
If you replace your ObjectId definition to the following
var ObjectId = Schema.Types.ObjectId;
your code should work correctly.

mongoose Foreign Key

I have a model called Portfolio that points to a user object using the user_id field. How can I model a many to one relationship with mongoose?
Portfolio
- user_id => is the id of a user object
Basically every portfolio object belongs to a user object.
I have the following code: Is this correct?
var PortfolioSchema = mongoose.Schema({
url: String,
createTime: { type: Date, default: Date.now },
updateTime: { type: Date, default: Date.now },
user:[
{type: Schema.Types.ObjectId, ref: 'User'}
]
});
Try this instead
var PortfolioSchema = mongoose.Schema({
url: String,
createTime: { type: Date, default: Date.now },
updateTime: { type: Date, default: Date.now },
user:{type: Schema.Types.ObjectId, ref: 'User'}
});

find all kinds but get one for every kind in mongodb

I create MessageScheme to save a message between two users, one document for one message. Now I want to find a list of people who have chated with specific person, what should I do?
I did this way, but it is not efficiency:
Message.find({$or: [{receiverId: specificId}, {senderId: specificId}]
}).sort('-created').limit(100).exec(function (err, results) {
res.jsonp(results) //the results will content all documents have specificId
})
This is the model in mongodb
var MessageSchema = new Schema({
created: {
type: Date,
default: Date.now
},
content: {
type: String,
default: '',
trim: true
},
senderId: {
type: String,
default: '',
},
receiverId:{
type: String,
default: '',
}
});