Virtual field AND real field - mongodb

Is it possible to have a virtual field that is also a field in a model?
var exampleSchema = new Schema({
name : {type: String, required: true}
slug:: {type: String}
});
exampleSchema.virtual('slug').get(function() {
if(this.slug && this.slug.length){
return this.slug;
}
return this.name.toLowerCase().replace(/ /g, '');
});
If slug is set I want to return the slug. If not, I want to return a computed value from name.
I don't want to use a static method, it needs to be a part of the result when pulled a record.

You can create a custom getter function and return the value if it exists, or the computed value if it doesn't.
var exampleSchema = new Schema({
name: {type: String, required: true}
slug: {
type: String,
get: function(value) {
if (value) {
return value;
} else {
return this.name.toLowerCase().replace(/ /g, '');
}
}
}
});

Related

mongoose set a default field to take value of 2 other fields

Is there a way to let one field take value of two other fields merged as default.
I have a user schema as follows:
const UserSchema = mongoose.Schema({
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},});
I want to add a third field called fullName that defaults to merging firstName + lastName
Is that possible in mongoose?
try this :
fullName:{
type:String,
required:true,
default: function(){
return this.firstName + " " + this.lastName
}}
on doc update :
yourSchema.pre("updateOne", function (next) {
this.set({ fullName: this.get("firstName") + " " + this.get("lastName") });
next();
});
I solved this using Virtual Setters (Virtuals) as documented by Mongoose
Make sure to add this to your Schema to include virtuals when you convert a document to JSON
const opts = { toJSON: { virtuals: true } };

Angular 2 Reactive Form nested group passed null on reset throw error

I have this form group:
Id: [null],
Nominativo: [null, [Validators.required, Validators.maxLength(100)]],
Area: fb.group({
Id: [null]
})
When i try to reset the form with this model:
Id: 1,
Nominativo: 'Test'
Area: null
the area null value throw exception "TypeError: Cannot read property 'Id' of null". My expected result is all Area value become null. I can avoid this problem? My server response with all nested model null when they are all null
I don't think there is a simple clean solution for this. You need to iterate the object properties and set the values manually. So something like this:
resetVal = {Id:1, Nominativo: 'Test', Area: null }
and when you receive the data, you first check if Area is null, if so, set the formcontrols to null in that formgroup. If not, then set the values you get from backend to your formgroup:
this.areaCtrl = this.myForm.controls.Area as FormGroup;
this.myForm.patchValue({
Id: this.resetVal.Id,
Nominativo: this.resetVal.Nominativo,
})
if(this.resetVal.Area === null) {
this.areaCtrl.patchValue({
Id: null
})
}
else {
for(let a in this.resetVal.Area) {
this.areaCtrl.patchValue({
[a]:this.resetVal.Area[a]
})
}
}
DEMO
I suggest to do something like this:
area.model.ts
export class Area {
id: string;
}
data.model.ts
export class DataModel {
id: string;
nominativo: string;
area: Area;
}
form.model.ts
export class FormModel {
id: string;
nominativo: string;
area?: Area;
}
data-model.service.ts
#Injectable()
export class DataModelService {
toFormModel(dataModel: DataModel): FormModel {
const form: FormModel = new FormModel();
form.id = dataModel.id;
form.nominativo = dataModel.nominativo;
if (dataModel.area) {
form.area = dataModel.area;
}
return form;
}
}
form.component.ts
constructor(dataModelService: DataModelService,
dataApi: dataApiService,
fb: FormBuilder) {
this.form = this.fb.group({
id: '',
nominativo: '',
area: this.fb.group({
id: ''
})
});
this.dataApi.getData()
.map((data: DataModel) => this.dataModelService.toFormModel(data))
.subscribe((formData) => {
this.form.patchValue(formData);
});
}

Mongodb: Not able to add new key in nested object

I have a schema in mongodb like
var schema = new mongoose.Schema({
agentCode: String,
data: {
type: Object,
profDtl: {
education: String
}
});
Now i want to add a new property desgnName in profDtl
var schema = new mongoose.Schema({
agentCode: String,
data: {
type: Object,
profDtl: {
desgnName: String, // trying to add new property
education: String
}
});
but it is not reflected in database
I got a solution for it, whenever add new property in mongodb schema, it required a default value to reflect on new entry
for Eg:
var schema = new mongoose.Schema({
agentCode: String,
data: {
type: Object,
profDtl: {
desgnName: {
type: String,
default: ""
},
education: String
}
});
now its working fine

Unable to query sub document mongoose

I've schema like this and i', trying to get the document from the array using _id. This is my first Mongo project that I'm working, please help me how can I achieve the. I basically want to retrieve the sub document corresponds to the id and update some data in that.
var PhoneSchema = new mongoose.Schema({
type: String,
number: String
});
var StudentSchema = new mongoose.Schema({
name: String,
dept: String,
phone: [PhoneSchema]
});
var Phone = mongoose.model('Phone',PhoneSchema);
var Student = mongoose.model('Student',StudentSchema);
I've tried the following ways, but none of them are working.
Method 1: When I tried the same in the console it is giving me the parent document along with the sub document that corresponds to the phoneId
Student.findOne({"phone._id":new mongoose.Schema.Types.ObjectId(phoneId) }, {'phone.$':1}, function(err, student) {
}
Method 2: As per the mongoose documentation to retrieve sub documents, in this case I'm getting exception saying phone is undefined
Student.phone.Id(phoneId);
I've fixed this by removing Schema from the below query
Student.findOne({"phone._id":new mongoose.Types.ObjectId(phoneId) }, {'phone.$':1}, function(err, student) {
}
i tried to solve your requirement. The following code did the job.
var PhoneSchema = new mongoose.Schema({
type: String,
number: String
});
var StudentSchema = new mongoose.Schema({
name: String,
dept: String,
phone: [PhoneSchema]
});
var Phone = mongoose.model('Phone',PhoneSchema);
var Student = mongoose.model('Student',StudentSchema);
var newPhone = new Phone({
type: 'ios', number: '9030204942'
});
var newStudent = new Student({
name:'Pankaj',
dept:'cse',
phone:newPhone
});
// newStudent.save(function(err, ph) {
// if (err) return console.error(err);
// });
Student.findOne({"phone._id":mongoose.Types.ObjectId('587e6409e06170ba1708dc21') },{_id:0,phone:1}, function(err, phone) {
if(err){
console.log(err)
}
console.log(phone);
});
Find the following screenshot with result

mongoose set: toLower not working on nested properties

I'm trying to normalize email addresses to lowercase before they are saved in the database. Setters on mongoose models are great for that and they work on simple models. However, when I try to set the toLower setter on a nested object where email is stored inside "owner" I get TypeError: Cannot call method 'toLowerCase' of undefined
function toLower (v) {
return v.toLowerCase();
}
This crashes:
var BusinessSchema = new mongoose.Schema({
owner: {
email: { type: String, required: 'Email adres mag niet leeg zijn.', set: toLower, get: toLower, index: { unique: true } },
password: { type: String, required: 'Wachtwoord mag niet leeg zijn.' }
}
});
This works:
var UserSchema = new Schema({
email: { type: String, set: toLower }
});
Because you're also using toLower as a getter, it's first called with a value of undefined when creating a new doc, then called again with the actual value. Regardless, your toLower function needs to protect itself so that it can be called with any value, not just strings.
So something like:
function toLower (v) {
if ('string' != typeof v) v = '';
return v.toLowerCase();
}
If you don't need the getter side of this, you could also just use the built-in lowercase setter:
var BusinessSchema = new mongoose.Schema({
owner: {
email: {
type: String,
required: 'Email adres mag niet leeg zijn.',
lowercase: true,
index: { unique: true }
},
password: { type: String, required: 'Wachtwoord mag niet leeg zijn.' }
}
});