Mongoose update gets no errors, but does not update - express

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)
})
}

Related

GraphQL - Parameters not being passed to backend in mutation

I've just started with GraphQL and mutations and am having this issue.
When I attempt to pass data to my GraphQL server, it seems the args parameter does not register the args that I am attempting to pass.
When I console.log them, they appear as undefined, but the method is working and receiving the request.
Does anything seem incorrect below? I'm just getting my head around it so would appreciate any feedback.
This is the query I'm attempting to run from GraphiQL
mutation {
addDelivery(
carrier: "AusPost",
goodsDelivered:[],
receiver: {
first_name:"ll",
last_name:"test",
receiver_email: "bbb#bbb.com.au"
},
consignmentNumber:"AAAA000",
poNumber:"PO0000"
) {
id
carrier {
iD
carrier_name
}
}
}
My schema:
type ReceiverType{
first_name: String
last_name: String
receiver_email: String
}
type ItemType {
item_type: String,
quantity: String
}
type Deliveries {
carrier: Carrier
consignmentNumber: String
goodsDelivered: [String]
id: ID
items: [ItemType]
poNumber: String
receiver: ReceiverType
}
type Carrier{
iD: ID
carrier_name: String
}
input Item {
item_type: String,
quantity: String
}
type Query {
deliveries: [Deliveries]
}
input Receiver {
first_name: String
last_name: String
receiver_email: String
}
type Mutation {
addDelivery(
carrier: String!,
consignmentNumber: String!,
goodsDelivered: [Item]!,
poNumber: String!,
receiver: [Receiver]!
) : Deliveries
}
My add delivery resolver
addDelivery: async (parent, args, context, info) => {
const delivery = new Deliveries({
receiver: {
first_name: args.first_name,
last_name: args.last_name,
receiver_email: args.receiver_email
},
items: args.items,
consignment_no: args.consignment_no,
po_number: args.po_number,
carrier_id: args.carrier_id,
delivery_id: args.delivery_id
});
await delivery.save();
return delivery;
}
I changed the signature to the following and it resolved the issue.
addDelivery: async ({receiver, items, consignment_no, po_number, carrier_id, delivery_id}) => {

How to remove element from an array in mongoose

I have the following Schema:
// userSchema
{
_id: Schema.ObjectId,
email: { type: String, unique: true },
password: String,
boxes: [boxSchema]
}
// boxSchema
{
_id: Schema.ObjectId,
boxId: { type: String, unique: true },
boxName: String
}
I have data like this:
{
_id: random,
email: em#i.l,
password: hash,
boxes: [{ "boxId" : "box1", "boxName" : "Box 1"},
{ "boxId" : "box2","boxName" : "Box 2"},
{ "boxId" : "box3","boxName" : "Box 3"}]
}
I am trying to remove an element from boxes array with boxId: box1 and the code I tried was this:
User.findOne({
_id: req.body.id
})
.then(function (user) {
if (user) {
for (i in user.boxes)
if (user.boxes[i].boxId === 'box1')
user.boxes[i].remove();
res.json('removed');
}
})
.catch(function (err) {
....
});
But what happens is that it removes all the boxes which is residing, instead of the boxId: box1
What about using filter
User.findOne({
_id: req.body.id
})
.then(function (user) {
if (user) {
user.boxes = user.boxes.filter(function(box){
return box.boxId !== 'box1'
})
res.json('removed');
}
})
.catch(function (err) {
....
});
There are many ways to remove element from the array and are as follows:
1) Delete(): using this function will remove the element but will not change the array size and keep blank object after removal of element.
2)splice(): It works similar to delete() but remove blank places in array after removal of element.
3)filter(): It takes function as an argument and removes the element efficiently.

document.invalidate gives empty json as response

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.
});

Mongoose relation not working both ways

I can't get a relationship running between my Rides and Comments controller in my app (built using the yeoman angular-fullstack generator).
Comment model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var CommentSchema = new Schema({
name: String,
comment: String,
active: Boolean,
ride: { type: mongoose.Schema.Types.ObjectId, ref: 'Ride' }
});
module.exports = mongoose.model('Comment', CommentSchema);
Ride model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var RideSchema = new Schema({
name: String,
distance: String,
climb: String,
rating: String,
active: Boolean,
comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }]
});
module.exports = mongoose.model('Ride', RideSchema);
Accessing /api/comments/ gives me a correct result, containing a related Ride:
{"_id":"54ce818f8c2889da58b01e19","name":"NAAM","comment":"COMMENT","ride":"54ce69647a78532057aa98e0","__v":0}]
Accessing /api/rides/ gives me the following result, without the corresponding Comments:
[{"_id":"54ce69647a78532057aa98e0","name":"Ride test ingevuld","distance":"4000","climb":"1200","rating":"1","__v":0,"comments":[]}]
Can anyone tell me what i am doing wrong?
Example from one of my projects:
exports.insertRoom = function(req, res) {
var id = req.body.id;
var r = req.body.room;
var room = new Room({name: r.name});
Floor.update(
{_id : id},
{
$push: { rooms: room}
},
{upsert:true},
function(floor, err)
{
res.sendStatus(200);
}
);
};
As far as I'am concerned it doesn't work like that. Your comments got it's ride, and your ride got it's comments. I think, you should remove
ride: { type: mongoose.Schema.Types.ObjectId, ref: 'Ride' }
and keep comments inside ride collection.
comments: ['Comment']
It is more objective solution as it supposed to be in MONGO DB which was designed for objective(hierarchial) data.

Transaction with Sequelize doesn't work

I want to build a simple webform where you can enter a persons firstname, lastname and select multiple groups for this person (but one for now)
I'm using node.js and sequelize to store the person in a MariaDB -Database.
Sequelize created the tables Persons, Groups and GroupsPersons according to the defined models.
var Sequelize = require("sequelize");
var sequelize = new Sequelize(config.database, config.username, config.password, config);
var Group = sequelize.define("Group", {
name: {
type: DataTypes.STRING,
allowNull: false
}
}
var Person = sequelize.define("Person", {
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING,
allowNull: false
}
}
Person.belongsToMany(Group, {as: 'Groups'});
Group.belongsToMany(Person, {as: 'Persons'});
Because creating the person and assigning it into a group should be handled atomically in one step I decided to use a transaction, shown in the docs here:
http://sequelize.readthedocs.org/en/latest/docs/transactions/#using-transactions-with-other-sequelize-methods
var newPerson = {
firstName: 'Hans',
lastName: 'Fischer'
}
var id = 3 // group
sequelize.transaction(function (t) {
return Person.create(newPerson, {transaction: t}).then(function (person) {
return Group.find(id, {transction: t}).then(function(group){
if (!group) throw Error("Group not found for id: " + id);
return person.setGroups( [group], {transction: t});
})
});
}).then(function (result) {
// Transaction has been committed
// result is whatever the result of the promise chain returned to the transaction callback is
console.log(result);
}).catch(function (err) {
// Transaction has been rolled back
// err is whatever rejected the promise chain returned to the transaction callback is
console.error(err);
});`
But for some reason neither function (result) {.. for success nor the function in catch gets called. However, the complete SQL queries of the transaction were generated except COMMIT, so nothing was inserted into the db.
If I put it like this
return person.setGroups( [], {transction: t});
the transactions succeeds, but with no inserts into GroupsPersons of course.
Any ideas or suggestions?
Thanks for help!
{transaction: t} was misspelled, it works now