Is it possible to only populate certain fields MongoDB - angularjs

I'm using the following model schema:
var AppointmentSchema = new Schema({
appointment_date: {type: Date},
created: {
type: Date,
default: Date.now
},
updated: {type: Date},
client: [{ type: Schema.Types.ObjectId, ref: 'User' }],
staff_id: [{ type: Schema.Types.ObjectId, ref: 'User' }],
cost:{
type: Number
},
jobDone:{
type: Boolean,
default: false
},
cancelled:{
type: Boolean,
default: false
}
});
Which clearly references the User model.
When I query I want to populate the client and staff data, but without some of the fields that they hold within that model.
So if the Users model is:
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
}
});
I would only want to populate with firstName and email (and omit the rest) is that possible?

To return a few specific fields returned for the populated documents, you need to pass the usual field name syntax as the second argument to the populate method:
Appointment
.findOne({ cancelled: true })
.populate('client', 'firstName displayName') // only return the User's firstName and displayName
.exec(function (err, appointment) {
if (err) return handleError(err);
console.log('The client name is %s', appointment.client.firstName);
// prints "The client name is Aaron"
console.log('The client display name is %s', appointment.client.displayName);
// prints "The client display name is aarontest'
})

Related

Why is my mongoose populate query throwing "Cannot populate path because it is not in your schema" error?

I'm building a form management program but right now I'm just trying to build a queue system to handle all the forms when they're assigned to someone.
when I call this first function, it should populate the elements of the activeWork array by pulling from each collection that the entries reference, there are several collections that could be referenced in active work, so I'm trying to use the collection type field to determine what collection to pull from, I don't know if I formatted any of this correctly because its my first time building any of this.
import statesPersons from "./statesPersons.schema.js";
export async function getStatesPersonsActiveWorkByProfileId(req, res){
try{
const { profileId } = req.params
const data = await statesPersons.find({profileId})
.populate('statesPersons.activeWork.referenceId')
return res.send({
message: "success",
data: data,
status: 200 })
}catch(e) {
console.error(e.message)
return res.send({
message: "couldn't fetch active work",
data: null,
status: 500 })
}
}
Here is the schema for statesPersons, the collection where active work is stored.
import mongoose, {model, Schema} from "mongoose";
const activeWorkSchema = new Schema({
active: Boolean,
collectionType: {
type: String,
enum: ['messages'],
},
referenceId: {
type: Schema.Types.ObjectId,
refPath: "statesPersons.activeWork.collectionType"
},
sentBy: {
type: Schema.Types.String,
ref: "statesPerson",
},
sentTo: {
type: Schema.Types.String,
ref: "statesPerson",
},
timeRecived: Date,
dueDate: Date,
subject: String,
viewed: Boolean,
content: {},
})
const statesPersonsSchema = new Schema({
profileId:{
type: String,
required: true,
unique: true
},
department: {
type: String,
required: true,
index: true,
},
firstName: String,
lastName: String,
location: String,
org: String,
title: String,
jobDescription: String,
email: {
type: String,
lowercase: true,
},
phoneNumber: String,
activeWork: [activeWorkSchema],
emailList: [String],
jobAssignments: [String],
affiantInfo: {
affiantInfoTitle: String,
affiantInfoExperience: String,
},
assessments: [
{
assessdBy: {
type: Schema.Types.ObjectId,
ref: "statesPerson",
},
dueDate: Date,
questions: {},
},
],
});
export default mongoose.model("statesPersons", statesPersonsSchema);
When I make a query, I get:
Cannot populate path statesPersons.activeWork.referenceId because it is not in your schema. Set the strictPopulate option to false to override.
I don't know if I formatted my populate correctly or if the problem is in my schema,

MEAN Angular up-voting function throwing forbidden message

What im trying to do is create an app where users can post items and others can vote on the items similar to Reddit etc.
Problem i have is that when one user votes on an item posted by another user they get a forbidden message.
How i do i make it so that one user can modify the votes count of another users item.
This is the model for the Item
var ItemSchema = new Schema({
title: {
type: String,
default: 'NA',
required: 'Please fill Item title',
trim: true
},
link: {
type: String,
required: 'Please fill Item URL',
trim: true
},
details: {
type: String,
default: 'NA',
required: 'Please fill Item Details',
trim: true
},
votes: {
type: Number,
default: '0'
},
voters: [{
type: Schema.ObjectId,
ref: 'User'
}],
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
So one user should be able to increment the upvotes for another users Item.
Routes
// Items collection routes
app.route('/items').all(itemsPolicy.isAllowed)
.get(items.list)
.post(items.create);
app.route('/items/itemCount').all()
.get(items.countitems);
app.route('/items/itemCountToday').all()
.get(items.countitemsToday);
// Single item routes
app.route('/items/:itemId').all(itemsPolicy.isAllowed)
.get(items.read)
.put(items.update)
.delete(items.delete);
Upvote function
$scope.upVoteHome = function(item) {
item.votes++;
item.$update(function() {
//$location.path('items/' + item._id);
}, function(errorResponse) {
// rollback votes on fail also
$scope.error = errorResponse.data.message;
});
};
Button
<button ng-show="authentication.user" ng-click="upVoteHome(item)" type="button"
class="btn btn-danger vote-up-button"><i class="glyphicon glyphicon-arrow-up"></i> Hot</button>
add a 'put' permission in the routing policy
{
roles: ['user'],
allows: [{
resources: '/deals',
permissions: ['get', 'post', 'put']
}, {
resources: '/deals/:dealId',
permissions: ['get', 'put']
}]
}

mongodb User with subdocument vs document with UserId

I am using meanjs and I would like to store some user data in a one to many relationship. My case is similar to the articles example but the articles will only ever be accessed through the user. I want the route to be something like
Users/:userId/articles
or
Users/me/articles
Question 1
Should I just stick with the articles model as it is or should I make articles a subdocument of user. e.g.
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
},
email: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
match: [/.+\#.+\..+/, 'Please fill a valid email address']
},
username: {
type: String,
unique: 'testing error message',
required: 'Please fill in a username',
trim: true
},
articles: [articleModel.schema],
password: {
type: String,
default: '',
validate: [validateLocalStrategyPassword, 'Password should be longer']
},
salt: {
type: String
},
provider: {
type: String,
required: 'Provider is required'
},
providerData: {},
additionalProvidersData: {},
roles: {
type: [{
type: String,
enum: ['user', 'store', 'admin']
}],
default: ['user']
},
updated: {
type: Date
},
created: {
type: Date,
default: Date.now
},
/* For reset password */
resetPasswordToken: {
type: String
},
resetPasswordExpires: {
type: Date
}
});
Question 2 if I make it a subdocument can I still use the $resource function or do I have to make custom functions?
The maximum BSON document size is 16 megabytes. The maximum document size helps ensure that a single document cannot use excessive amount of RAM or, during transmission, excessive amount of bandwidth. To store documents larger than the maximum size, MongoDB provides the GridFS API.

Mongo Giving 'duplicate key error' on non-unique fields

I am getting a MongoDB error when trying to insert a subdocument. The subdocs already have unique _ids, but an error is being thrown for a different, non-unique field that I don't want unique.
The error in Angular is: "Assets.serial already exist". How can I make this field contain duplicate values, and what is causing the model to assume it should be unique?
Here is my Mongoose model:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var AssetUrlSchema = new Schema({
name: {
type: String,
unique: false,
default: '',
trim: true
},
url: {
type: String,
unique: false,
default: 'http://placehold.it/75x75',
trim: true
},
}),
AssetSchema = new Schema({
serial: {
type: Number,
unique: false
},
urls: {
type: [AssetUrlSchema],
unique: false,
default: [
{ name: '', url: 'http://placehold.it/75x75' },
{ name: '', url: 'http://placehold.it/75x75' }
]
}
}),
/**
* Item Schema
*/
ItemSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please enter name',
trim: true
},
assets: {
type: [AssetSchema],
default: [],
unique: false
},
property: {
type: Schema.ObjectId,
zd: 'Please select a property',
ref: 'Property'
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Item', ItemSchema);
And here is my 'save' method:
function(){
var i = 0, assets = [];
for (;i < 24;i++) {
assets.push({
serial: 1000+i,
urls: {
name: 'Asset Name ' + i,
url: 'http://placehold.it/75x75?'
}
});
}
item = new Items ({
name: 'FPO',
property: newPropId,
assets: assets
});
return item.$save(
function(response){ return response; },
function(errorResponse) {
$scope.error = errorResponse.data.message;
}
);
}
The first time I insert a document, it works fine. Any subsequent time, it fails with a 400 because the assets.serial field is not unique. However, I am specifically marking that field as unique:false.
The error in the mode console is:
{ [MongoError: insertDocument :: caused by :: 11000 E11000 duplicate key error index: mean-dev.items.$assets.serial_1 dup key: { : 1000 }]
name: 'MongoError',
code: 11000,
err: 'insertDocument :: caused by :: 11000 E11000 duplicate key error index: mean-dev.items.$assets.serial_1 dup key: { : 1000 }' }
POST /api/items 400 14.347 ms - 41
Mongoose doesn't remove existing indexes so you'll need to explicitly drop the index to get rid of it. In the shell:
> db.items.dropIndex('assets.serial_1')
This will happen if you initially define that field unique: true but then later remove that from the schema definition or change it to unique: false.
If you're using MongoAtlas, you can go to the collection -> click 'indexes' -> on the index you want to delete, click 'drop index'
If you are in a dev/prototype mode, simply deleting the actual collection (after changing the unique:true to false for instance), will reset everything and mongoose will allow your duplicates.

Bad request in MEAN stack app trying to append to an array in a schema

I am trying to pass an array of interest rates to a mongoose schema consisting of accounts.
I want to store interest rates that change at certain dates.
However, when I trigger the create function my dev tools tell me I have done something bad:
**400 Bad Request**
I have been using this as a template.
The view: has been disconnected so that I only pass:
var interest = {
rate: 1,
date: Date.now()
};
The controller that does the updating:
// Create new Account
$scope.create = function() {
// Create new Account object
var account = new Accounts ({
name: this.name,
desc: this.desc,
interests: []
});
// PROBLEMATIC PART
// Store interest:
var interest = {
rate: 1,
date: Date.now()
};
account.interests.push(interest);
// PROBLEMATIC PART END
// Redirect after save
account.$save(function(response) {
$location.path('accounts/' + response._id);
// Clear form fields
$scope.name = '';
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
The mongoose schema:
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
*
* Interest Rate Schema
*/
var InterestRate = new Schema({
rate:{
type: Number,
default: 0,
trim: true
},
date:{
type : Date,
default: '',
required: 'When is the interest to be updated',
trim: true
}
});
/**
* Account Schema
*/
var AccountSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Account name',
trim: true
},
desc:{
type: String,
default: '',
trim: true
},
interests:
[{ type : Schema.Types.ObjectId, ref: 'InterestRate' }],
amount:{
type: Number,
default:0,
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Account', AccountSchema);
you can try by leaving the interest rate as a frond end structure and not define it in the model, then in the account schema set interests as type of [] and just push the objects
var AccountSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Account name',
trim: true
},
desc:{
type: String,
default: '',
trim: true
},
interests:
type:[],
default:[]
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
just like this

Resources