I wanted to check if the body in a document is unique. If not unique give appropriate error.
NewsSchema.pre("save", true, function (next: any, done: any) {
var self = this;
News.findOne({body: self.body}, "body", function (err: any, body: string) {
if(err)
done(err);
else if(body) {
self.invalidate("body", "the news body already exists", self.body);
done(new Error("the news body already exists"));
}
else {
next();
}
});
});
When intentionally giving a duplicate body. It returns with an empty json. Whereas I was expecting it to be:
{
message: 'Validation failed',
name: 'ValidationError',
errors:
{
size:
{
message: 'the news body already exists',
name: 'ValidatorError',
path: 'body',
type: 'String',
value: 'some string'
}
}
}
you need to use validate() to check if it is valid or not.
var self = this; //type document
...
self.invalidate("body", "the news body already exists", self.body);
//use validate() to check the validity
self.validate(function(err){
console.log(err);//this will give you your expected results.
});
Related
Cant figure out what I'm missing, and I havent had this issue before on any of my other updates. I expanded a collection and want to be able to update certain fields depending on where in the app the user is interacting. I've had no issue working with subdocs using separate calls, but with this particular nested field I'm getting no errors, and getting the correct document returned without the update. (I have another nested field that is updating fine - "personalInfo" while the "medical" field is the one giving me trouble)
The model looks like this:
const clientSchema = new Schema({
fullName: String,
firstName: String,
lastName: String,
enrollment: {
enrolled: Boolean,
enrollDates: [
{
begin: Date,
end: Date
}
]
},
personalInfo: {
dateOfBirth: Date,
phone: String,
email: String,
address: {
addressLineOne: String,
addressLineTwo: String,
city: String,
state: String,
zip: String
},
regionalCenter: String,
serviceCoordinator: String,
serviceCoordinatorPhone: String,
rcId: String,
emergencyContact: String,
livingSituation: String,
ihss: {
provider: String,
hours: Number,
services: String
}
},
medical: {
primaryIns: String,
primaryInsId: String,
secondaryIns: String,
secondaryInsId: String,
hasMediCal: Boolean,
mediCalId: String,
mediCalEnroll: Date,
hasMedicare: Boolean,
medicareId: String,
medicareEnroll: Date,
logs: {type: [logSchema], default: []},
},
contracts: {type: [contractSchema], default: []},
visits: [{ type: Schema.Types.ObjectId, ref:'Visit' }],
users: [{ type: Schema.Types.ObjectId, ref: 'User' }],
servicePlans: [{ type: Schema.Types.ObjectId, ref: 'ServicePlan'}],
currentPlan: String,
income: {type: [incomeSchema], default: []},
contacts: {type: [contactSchema], default: []}
}
The route:
router.route("/clients/:clientId").patch(updateClient)
And the controller... since I want to keep the controller as restful as possible, but conditionally set the fields depending on the api call, I conditionally set the different aspects and then pass in the body an additional field to tell the controller which aspect to update (so the personalInfo section has a field "personalInfo": "personalInfo" and the medicalInfo field has its own. The personalInfo object updates fine (I commented out the initial line since it was stated in another post that these calls work better doing a findOneAndUpdate- but that hasnt yielded any progress, and the personalInfo update worked without issue).
exports.updateClient = async (req, res) => {
try {
//const client = await Client.findOne({ _id: req.params.clientId })
if (req.body.firstName) {
client.firstName = req.body.firstName
}
if (req.body.lastName) {
client.lastName = req.body.lastName
}
if (req.body.personalInfo === 'personalInfo') {
client.updateOne({$set: {personalInfo: req.body}}, {new: true}, function(err, updatedDoc){
if(err){
console.log("error updating personal info: ", err)
}
})
}
if (req.body.enrollment === 'enrollment') {
client.updateOne({$set: {enrollment: req.body}}, {new: true}, function(err, updatedDoc){
if(err){
console.log("error updating personal info: ", err)
}
})
}
if(req.body.medicalInfo === 'medicalInfo'){
console.log("medInfo: ", req.body)
let clientId = req.params.clientId
// const client = await Client.findById(clientId)
// console.log("Client ", client)
// client.medical.set(req.body)
Client.findById(clientId)
.then((client) => {
client.medical.set(req.body
// hasMediCal: req.body.hasMediCal,
// hasMedicare: req.body.hasMedicare,
// mediCalId: req.body.mediCalId,
// medicareId: req.body.medicareId,
// mediCalEnroll: req.body.mediCalEnroll,
// medicareEnroll: req.body.medicareEnroll,
// primaryIns: req.body.primaryIns,
// primaryInsId: req.body.primaryInsId,
// secondaryIns: req.body.secondaryIns,
// secondaryInsId: req.body.secondaryInsId
);
client.save();
res.send(client)
})
// Client.findOneAndUpdate(
// { _id: req.params.clientId},
// {$set: {medical: req.body}},
// {new: true},
// function(err, updatedDoc){
// if(err){
// console.log("error updating personal info: ", err)
// }
// })
// client.markModified('medical');
}
// await client.save()
// res.send(client)
} catch (error) {
res.status(404)
res.send({ error: "Client not updated: ", error})
}
}
Finally, the body being sent:
{
"hasMediCal": false,
"hasMedicare": false,
"mediCalEnroll": "2005-04-22T08:00:00",
"mediCalId": "91234567A",
"medicalInfo": "medicalInfo",
"medicareEnroll": "2005-04-03T08:00:00",
"medicareId": "9FHS-ASU-95F8",
"primaryIns": "Molina",
"primaryInsId": "91234567A",
"secondaryIns": "SilverScript - Rx",
"secondaryInsId": "08dfA8d8"
}
Whether I've tried findOneAndUpdate, or findOne and then setting the field on the result, or setting each subfield in the object specifically, I keep getting the correct document returned, just not updated, and with no errors. I thought possibly it was because I was attempting to set the update within the conditionals, so I created a separate update controller but that got the same results as well. Really lost as how else to pursue this.
Please let me know if you see anything missing or where I'm going wrong. Much appreciated.
So after running around on this for hours, I came to a working solution, which essentially is no different, other than setting the query as a variable rather than writing it out. If anyone has any guess as to why this works when the multiple other methods didnt, I'd be grateful for your thoughts.
if(req.body.medicalInfo === 'medicalInfo'){
console.log("medInfo: ", req.body)
let clientId = req.params.clientId
let query = {_id: clientId};
Client.findOneAndUpdate(query, {$set: {medical: req.body}}, {new: true, upsert: true}, function(err, doc){
if(err) return res.status(500).send( {error:err});
return res.send(doc)
})
}
see below error message and source code, doesn't work even after I added person fields of photos:
TypeError: Cannot read properties of undefined (reading 'url')
var p = google.people("v1");
p.people.get(
{
resourceName: "people/me",
personFields: "names,emailAddresses,photos",
auth: oauth2Client,
},
function (err, user) {
if (err) { return; }
res.json({
name: encoder.htmlEncode(user.displayName),
picture: user.image.url,
});
}
);
You should have a look into the docs. The people.get request returns a Person object. And such a Person does not have an image property, so you cant't access user.image.url because user.image does not exist. Neither does user.displayName, btw.
What a Person actually looks like is as follows (the ... meaning there are additional properties too, look up in the docs, if you need more)
{
...
coverPhotos: [{url: "https://url.to/image", ...}],
...
names: [{ displayName: "John Doe", ...}],
...
}
So to get the name and picture, first of all, instead of photos you need to request coverPhotos. Then you can extract the desired values, as follow:
p.people.get(
{
resourceName: "people/me",
personFields: "names,emailAddresses,coverPhotos",
auth: oauth2Client,
},
function (err, user) {
if (err) { return; }
let
name = user.names?.[0]?.displayName || "John Doe",
url = user.coverPhotos?.[0]?.url
res.json({
name: encoder.htmlEncode(name),
picture: user.image.url,
});
});
I used the conditional chaining ?. here, to make sure, this code does not run into an exception if for instance coverPhotos does not exist or is an empty array.
I need your help to adapt a code that displays if a username is already taken.
This code is working :
$(document).ready(function()
{
$("#name").keyup(function()
{
var name = $(this).val();
$.post( "username-check.php", { name: $("#name").val() }, function (data){
if(data=='1'){
//the php post result is equal to '1' if the username is already taken.
// This actualy display "1" in the form if the username is taken.
$("#result").html(data);
}
}); //function(data)
});
})
I got this code from a website, to check and validate the inputs of my form
$('document').ready(function()
{
// Check and validate the username input
var nameregex = /^[a-zA-Z0-9 ]+$/;
$.validator.addMethod("validname", function( value, element ) {
return this.optional( element ) || nameregex.test( value );
});
/* To check if the username is taken I think I have to add something like that :
var checkusernameregex = ??????;
$.validator.addMethod("checkusername", function( value, element ) {
return this.optional( element ) || checkusernameregex.test( value );
}); */
$("#register-form").validate({
rules:
{
name: {
required: true,
validname: true,
//chekusername : true,
minlength: 5,
maxlength: 25
}
},
messages:
{
name: {
required: "Please choose a username",
validname: "Username can only have alphanumerical characters ",
//checkusername: "Username already taken";
minlength: "Username is too short"
}
},
});
//to display errors code, but not needed for my actual request
Thank you
A contrived example of bi-directional data binding
var user = {
model: function(name) {
this.name = m.prop(name);
},
controller: function() {
return {user: new user.model("John Doe")};
},
view: function(controller) {
m.render("body", [
m("input", {onchange: m.withAttr("value", controller.user.name), value: controller.user.name()})
]);
}
};
https://lhorie.github.io/mithril/mithril.withAttr.html
I tried the above code does not work nothing.
It was the first to try to append the following.
m.mount(document.body, user);
Uncaught SyntaxError: Unexpected token n
Then I tried to append the following.
var users = m.prop([]);
var error = m.prop("");
m.request({method: "GET", url: "/users/index.php"})
.then(users, error);
▼/users/index.php
<?php
echo '[{name: "John"}, {name: "Mary"}]';
Uncaught SyntaxError: Unexpected token n
How do I operate the m.withAttr tutorials code?
Try returning m('body', [...]) from your controller.
view: function (ctrl) {
return m("body", [
...
]);
}
render should not be used inside of Mithril components (render is only used to mount Mithril components on existing DOM nodes).
The example is difficult to operate because it's contrived, it's not meant to be working out-of-the-box. Here's a slightly modified, working version:
http://jsfiddle.net/ciscoheat/8dwenn02/2/
var user = {
model: function(name) {
this.name = m.prop(name);
},
controller: function() {
return {user: new user.model("John Doe")};
},
view: function(controller) {
return [
m("input", {
oninput: m.withAttr("value", controller.user.name),
value: controller.user.name()
}),
m("h1", controller.user.name())
];
}
};
m.mount(document.body, user);
Changes made:
m.mount injects html inside the element specified as first parameter, so rendering a body element in view will make a body inside a body.
Changed the input field event to oninput for instant feedback, and added a h1 to display the model, so you can see it changing when the input field changes.
Using m.request
Another example how to make an ajax request that displays the retrieved data, as per your modifications:
http://jsfiddle.net/ciscoheat/3senfh9c/
var userList = {
controller: function() {
var users = m.prop([]);
var error = m.prop("");
m.request({
method: "GET",
url: "http://jsonplaceholder.typicode.com/users",
}).then(users, error);
return { users: users, error: error };
},
view: function(controller) {
return [
controller.users().map(function(u) {
return m("div", u.name)
}),
controller.error() ? m(".error", {style: "color:red"}, "Error: " + controller.error()) : null
];
}
};
m.mount(document.body, userList);
The Unexpected token n error can happen if the requested url doesn't return valid JSON, so you need to fix the JSON data in /users/index.php to make it work with your own code. There are no quotes around the name field.
In my app I want define JSON schemas for custom API.
For example from: http://docs.strongloop.com/display/public/LB/Remote+methods#Remotemethods-Example
module.exports = function(Person){
Person.greet = function(msg, cb) {
cb(null, 'Greetings... ' + msg);
}
Person.remoteMethod(
'greet',
{
accepts: <generate definitions from jsonschema>,
returns: <generate definitions from jsonschema>
}
);
};
How to do that?
This is right way?
MY SOLUTION - validation decorator + remote method params with object type
var validate = require('jsonschema').validate;
bySchema = function (schema) {
return function (func) {
return function () {
var data = arguments[0],
callback = arguments[1];
var result = validate(data, schema);
if (result.errors.length > 0) {
// some errors in request body
callback(null, {
success: false,
error: 'schema validation error',
});
return;
}
return func.apply(this, arguments);
};
};
};
defaultRemoteArguments = {
accepts: {
arg: 'data',
type: 'object',
http: function(ctx) {
return ctx.req.body;
}
},
returns: {
arg: 'data',
type: 'object',
root: true
}
};
Example:
Auth.login = bySchema(require('<path to shcemajson json for this request>'))
(function(data, cb) {
// process request
});
Auth.remoteMethod('login', defaultRemoteArguments);
In this solution contrib loopback explorer will not be useful, because request/response are objects, not fields...
The correct way to do it is to set the type in the returns attribute to the model name.
In your case you would write:
Person.remoteMethod(
'greet',
{
...
returns: {type:'Person', ...}
}
);
You need to modify your output to match the format accepted by the returns property.
...
returns: [{arg: "key1", type: "string"}, {arg: "key2", type: "object"}, ...];
...