Define a function as a default in a field in mongoose - javascript

I want to do something like this:
var categorySchema = new Schema({
id: {
unique: true,
default: function() {
//set the last item inserted id + 1 as the current value.
}
},
name: String
});
This is posible?.

var categorySchema = new Schema({
id : {
type : Number
},
name : {
type : String
}
});
// Define a pre-save method for categorySchema
categorySchema.pre('save', function(next) {
var self = this;
// Example of your function where you get the last ID
getLastId(function(id){
// Assigning the id property and calling next() to continue
self.id = id;
next();
});
});

Related

Mongoose Schema method: Error - model method is not a function

I have two Mongoose model schemas as follows. The LabReport model contains an array of the referenced SoilLab model. There is a static method in the SoilLab model that I was using to select which fields to display when LabReport is retrieved.
//LabReport.js
var mongoose = require("mongoose");
var SoilLab = mongoose.model("SoilLab");
var LabReportSchema = new mongoose.Schema(
{
labFarm: { type: mongoose.Schema.Types.ObjectId, ref: "Farm" },
testName: { type: String },
soilLabs: [{ type: mongoose.Schema.Types.ObjectId, ref: "SoilLab" }],
},
{ timestamps: true, usePushEach: true }
);
LabReportSchema.methods.toLabToJSON = function () {
return {
labReport_id: this._id,
testName: this.testName,
soilLabs: this.soilLabs.SoilToLabJSON(),
};
};
mongoose.model("LabReport", LabReportSchema);
//SoilLab.js
var mongoose = require("mongoose");
var SoilLabSchema = new mongoose.Schema(
{
description: { type: String },
sampleDate: { type: Date },
source: { type: String },
},
{ timestamps: true, usePushEach: true }
);
SoilLabSchema.methods.SoilToLabJSON = function () {
return {
description: this.description,
sampleDate: this.sampleDate,
source: this.source,
};
};
mongoose.model("SoilLab", SoilLabSchema);
When I try to retrieve the LabReport, I get "this.soilLabs.SoilToLabJSON is not a function". This is how I'm trying to retrieve LabReport.
//labReports.js
...
return Promise.all([
LabReport.find()
.populate("soilLabs")
.exec(),
LabReport.count(query).exec(),
req.payload ? User.findById(req.payload.id) : null,
]).then(function (results) {
var labReports = results[0];
var labReportsCount = results[1];
var user = results[2];
return res.json({
labReports: labReports.map(function (labReport) {
return labReport.toLabToJSON(user); //This cant find SoilToLabJSON
}),
If I remove the .SoilToLabJSON in LabReport.js and just call this.soilLabs, it works but outputs all of the soilLabs data which will become an issue when I have the model completed with more data. I have dug into statics vs methods a little and tried changing it to statics but it didn't work.
I get the soilLabs to populate but not sure why the .SoilToLabJSON method is inaccessible at this point. Do I need to find() or populate the soilLab differently? Is the method incorrect?
labReport.toLabToJSON is passing an array and that was causing the error for me. I simply edited the LabReport.js to the following to take the array and map it to SoilToLabJSON properly.
myTestSoilLabOutput = function (soilLabs) {
var test = soilLabs.map(function (soilLab) {
return soilLab.SoilToLabJSON();
});
return test;
Changed the LabReportSchema.methods.toLabToJSON to:
LabReportSchema.methods.toLabToJSON = function () {
return {
labReport_id: this._id,
testName: this.testName,
soilLabs: myTestSoilLabOutput(this.soilLabs),
};
};

Updating a shadow field, via updateOne pre hook, in mongoose?

Can anyone explain how to use the updateOne pre-hook, in mongoose (5.9.5)?
I am need to create a normalised 'shadow field' (not sure the right term) to help with certain searches. While I am able to update the shadow field during a save, I am having trouble during update.
The save pre-hook:
personSchema.pre('save', function (next) {
if (this.isModified('name')) {
const name = this.name;
if (name && name.trim().length > 0) {
const shadowName = name.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
this.shadowName = shadowName.toLowerCase();
} else {;
this.shadowName = name;
}
}
// do stuff
next();
});
Doing the equivalent for updateOne does not seem to work (shadowName stays with the value it was given during the initial save):
personSchema.pre('updateOne', function (next) {
const name = this.name;
if (name && name.trim().length > 0) {
const shadowName = name.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
this.update({}, { shadowName: shadowName.toLowerCase() });
} else {
this.shadowName = name;
}
// do stuff
next();
});
The schema:
const personSchema = new mongoose.Schema({
resourceId: {
type: String,
required: true,
unique: true,
index: true,
uppercase: true
},
name:{
type: String,
required:true,
index: true
},
// can be used for searches, but don't update directly
shadowName: {
type: String,
index: true
},
});
BTW I can confirm the hook is called, but the field is not updated.
Turns out you can't access the field values directly and instead need to leverage the get() and set() methods on the query.
Changing the pre-updateOne hook to be the following works:
personSchema.pre('updateOne', function (next) {
const name = this.get('name');
if (name && name.trim().length > 0) {
const shadowName = name.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
this.set('shadowName', shadowName.toLowerCase());
} else {
this.set('shadowName', name);
}
// do stuff
next();
});

node Sequelize how to write static functions

I have experience in writing statics functions in moongose like
var mongoose =require('mongoose');
var Schema = mongoose.Schema;
var adminSchema = new Schema({
fullname : String,
number : Number,
email: String,
auth : {
username: String,
password : String,
salt: String
}
});
adminSchema.statics.usernameInUse = function (username, callback) {
this.findOne({ 'auth.username' : username }, function (err, doc) {
if (err) callback(err);
else if (doc) callback(null, true);
else callback(null, false);
});
};
here usernameInUse is the function I wana write but using sequelize for mysql database
my model
/*
This module is attendant_user table model.
It will store attendants accounts details.
*/
"use strict";
module.exports = function(sequelize, DataTypes) {
var AttendantUser = sequelize.define('AttendantUser', {
username : {
type : DataTypes.STRING,
allowNull : false,
validate : {
isAlpha : true
}
},{
freezeTableName : true,
paranoid : true
});
return AttendantUser;
};
How to add statics function here..??
Well, you can easily use Expansion of models
var User = sequelize.define('user', { firstname: Sequelize.STRING });
// Adding a class level method
User.classLevelMethod = function() {
return 'foo';
};
// Adding an instance level method
User.prototype.instanceLevelMethod = function() {
return 'bar';
};
OR in some cases you may use getter and setter on your models. See the docs:
A) Defining as part of a property:
var Employee = sequelize.define('employee', {
name: {
type : Sequelize.STRING,
allowNull: false,
get : function() {
var title = this.getDataValue('title');
// 'this' allows you to access attributes of the instance
return this.getDataValue('name') + ' (' + title + ')';
},
},
title: {
type : Sequelize.STRING,
allowNull: false,
set : function(val) {
this.setDataValue('title', val.toUpperCase());
}
}
});
Employee
.create({ name: 'John Doe', title: 'senior engineer' })
.then(function(employee) {
console.log(employee.get('name')); // John Doe (SENIOR ENGINEER)
console.log(employee.get('title')); // SENIOR ENGINEER
})
B) Defining as part of the model:
var Foo = sequelize.define('foo', {
firstname: Sequelize.STRING,
lastname: Sequelize.STRING
}, {
getterMethods : {
fullName : function() { return this.firstname + ' ' + this.lastname }
},
setterMethods : {
fullName : function(value) {
var names = value.split(' ');
this.setDataValue('firstname', names.slice(0, -1).join(' '));
this.setDataValue('lastname', names.slice(-1).join(' '));
},
}
});
Hope it helps.
AttendantUser.usernameInUse = function (username, callback) {
...
};
return AttendantUser;

Retrieve value from parent in MongoDB sub-document

I have two schemas
childrenSchema = new Schema({
name: String
});
parentSchema = new Schema({
type: String,
children: [childrenSchema]
});
Now I want a method in childrenSchema from which I retrieve the type of the parent. I guess it is something like
childrenSchema.methods.generateName = () => {
// get parent type
};
Do there exist a function like this.parent().type, i.e.
childrenSchema.methods.generateName = () => {
// get parent type
return this.parent().type;
};
You can do like this :
childrenSchema = new Schema({
name: String
});
childrenSchema.methods.generateName = () => {
// get parent type
return this.ownerDocument().type;
};
parentSchema = new Schema({
type: String,
children: [childrenSchema]
});
var childModel = mongoose.model('Children', childrenSchema);
var parentModel = mongoose.model('Parent', parentSchema);
var parent = new parentModel({type: 'Scifi'});
parent.children.push(new childModel({name: 'Star wars'}));
parent.save(function(err, doc){
console.log(doc.children[0].generateName()); // Scifi
});

In mongoose how to iterate over array of ObjectId?

I try to refactor from javascript object to mongoose object.
I have two simple models:
Candidate model:
var candidateSchema = new Schema({
name: String,
score: { type: Number, default: 0, min: -2, max: 2 }
});
candidateSchema.methods.updateScore = function updateScore(newScore) {
this.score = newScore;
};
Vote model containing a list of candidate:
var voteSchema = new Schema({
candidates: [
{ type: Schema.Types.ObjectId, ref: 'Candidate' }
]
});
function candidateAlreadyExists(candidates, newCandidate) {
var alreadyExists = false;
candidates.forEach(function (candidate) {
if (newCandidate.name === candidate.name) {
alreadyExists = true;
}
});
return alreadyExists;
}
voteSchema.methods.addCandidate = function addCandidate(newCandidate, callback) {
var candidates = this.candidates;
if (!candidateAlreadyExists(candidates, newCandidate)) {
candidates.push(newCandidate);
}
this.save(callback);
};
I try to add a static method in my voteSchema to add a new candidate, only if it doesn't exist.
I can't iterate over my candidates (candidates.forEach(function (candidate) {) because it's an array of _ids and not an array of javascript objects
Someone have an idea ?
It would be better to use $addToSet to let MongoDB do that for you atomically.
voteSchema.methods.addCandidate = function addCandidate(newCandidate, callback) {
this.candidates.addToSet(newCandidate._id);
this.save(callback);
};

Categories

Resources