How to update document in mongo with nested schema - node.js

I have the following code:
add_new_patient : function(username,pname,pid,pdesc,callback){
var find_md = function(){
return function(err,pat){
if (err){
console.log('Error at adding patient: error at searching for users');
callback(2);//In the callback method I'm passing I have specific behavior for error handling for error codes.
return;
}
if (pat.lenth > 0){
console.log('searching for md');
MD.find({'mdname':username},add_patient(pat));
}else{
console.log('Error at adding patient: no user found');
callback(-1);
return;
}
}}
var add_patient = function(pat){
return function(err,md){
if (err){
console.log('Error at adding patient: cannot find md');
callback(-1);
return;
}
callback(0);
}
}
console.log('searching for user '+pid);
User.find({'name':pid},find_md());
}
And these are my schemas:
var mdSchema = mongoose.Schema({
mdname : String,
pacients : [userSchema.ObjectId]
});
var userSchema =mongoose.Schema({
name : String,
password : String,
phone : String,
history : [{timestamp: Date , heart: Number }],
md : {mdname: String, contact: Number}
});
As you can guess from the code I want to add patients to the dms. First I search for the pid in the database. If I find a patient I start to look for mds. When I find the md I want to add the patient to the md. Now I don't know how to add them. The schema shows that I have an array of schemaUser, which is the type of patient, but I don't know how to append to it, not how to create an MD model from object from the data I received from the query. Also what should I insert into the array of patients? The _id of the found patient or the whole object?

I managed to solve it in the following way:
var add_patient = function(pat){
return function(err,md){
if (err){
console.log('Error at adding patient: cannot find md');
callback(-1);
return;
}
var query = {mdname: md.mdname};
console.log(md);
var doThis = { $addToSet: { patients: pat._id } };
console.log(query);
MD.update(query,doThis,done_adding());
}
}
var done_adding = function(){
return function(err,dat){
if (err){
console.log('Error at the end of adding new patient!');
callback(-1);
return;
}
console.log('new patient added');
callback(0);
}
So what this does is: when I have the md to whom I want to add a patient/user I use the update method, with the $addToSet operation so I will have a set of patients associated with an md. I don't know why, but the same code did not work for me with the $push parameter. Then simply nothing happened and when I set the upsert option to true my whole record in the database was overwritten by the id.

Related

How to retrieve document in mongoose

I have multiple document in collection having a long string in each document, I want to retrieve one document at time, I dont have anything in document except long string, how can I retrieve that?
I inserted all document in collection using insertMany(), here is my code and output when I retrieved all document
var schema = new mongoose.Schema({
question : String,
id: Number
})
var quizz = mongoose.model('Quiz', schema );
var firstDoc = new quizz({
question: 'question 1',
id: 1
})
var secondDoc = new quizz({
question: 'question 2',
id: 2
var question_data = [firstDoc, secondDoc];
quizz.insertMany(question_data, function(err, res){
if(err){
console.log("error occured while saving document object " + err )
}else{
console.log("saved data");
}
})
quizz.findOne({id : '1'}, function(err, res){
if(err){
console.log(err)
}else{
console.log(res);
}
})
insertMany Will return you the list of _ids that have been created for your documents you've inserted. You can then pull out each document based on the _ids individually
quizz.insertMany(question_data, function(err, res){
if(err){
console.log("error occured while saving document object " + err )
}else{
console.dir(res); // res has the _ids.
console.log("saved data");
}
})
http://mongoosejs.com/docs/api.html#model_Model.insertMany
Alternatively if you always want to ensure ordering you could add a sequence column to the question, and/or put all questions inside one quizz.
if you want to do something with the _id of the documents that was inserted into the collection then use the answer of Kevin, but if you want to just do something with them later, you can use .find() which return you all the documents that are in the collection.
quizz.find(function(err, docs) {
//docs = array of all the docs in the collections
})
if you want specific by id:
quizz.findOne({_id: id},function(err, doc) {
//doc = the specific doc
})
if you want specific by strong
quizz.findOne({question: "question 3"},function(err, doc) {
//doc = the first (!!!) doc that have question in his `question` attribute
})
or if you want all the docs that have question 3 in them:
quizz.find({question: "question 3"},function(err, docs) {
//docs = array with all the docs that have "question 3" there, (return array even if only 1 found)
})

Unable to delete a document with passed "email" and "_id" anyhow

I wanted to delete a document with concerned _id and email when I click on "Remove task" in the HTML file.
Following is the code which removes that task:
I've passed value of email and _id(only hexadcemial string value) to the code:
collection.findOneAndDelete({email:email,_id:taskid},function (err, result) {
if (err) {
console.log(err);
} else {
console.log("Removed!");
console.log(result);
callback(result);
}
db.close();
});
But, the function is not recognizing _id that I've passed. The value of "taskid" variable is 566836bd8db43d3d56e23a4a i.e. only strings value from _id:
ObjectId("566836bd8db43d3d56e23a4a")
var taskid=566836bd8db43d3d56e23a4a;
I've tried every possible declaration of taskid to convert it so that the function could recognize the value of _id and match it:
var taskid= "ObjectId("+'"'+req.param('taskid')+'"'+")";
But till now, I am not able to match the _id with the taskid. Any fix?
if you are going to compare with ObjectId then
var ObjectId = require('mongoose').Types.ObjectId
collection.findOneAndDelete({email:email,_id:new ObjectId(taskid)},function (err, result) {
if (err) {
console.log(err);
} else {
console.log("Removed!");
console.log(result);
callback(result);
}
db.close();
});
Should work for you.
If you feel the job too hard for each and every query then you can create an new method.
String.prototype.toObjectId = function() {
var ObjectId = (require('mongoose').Types.ObjectId);
return new ObjectId(this.toString());
};
// Every String can be casted in ObjectId now
console.log('545f489dea12346454ae793b'.toObjectId());

Mongoose: which are the Number type limits?

I'm building a node app, with mongodb through mongoose.
I define a 'phone' field of type Number for my person model.
I save ~550 persons with no problem.
When I try to save a person with a specific number ("3932978***", last 3 digits obscured for privacy reasons), I get a cast error:‬
... at process._tickCallback (node.js:355:11)","message":"Cast to Number failed for value \"3932978***‬\" at path \"phone\"","name":"CastError","kind":"Number","value":"3932970***‬","path":"phone"}}}
Is it possible I'm hitting a Mongoose Number limit? Effectively, that number seems to be the biggest among other phone number values, but it is not near a power of 2...
I am completely confused... Can you shed some light?
UPDATE: I add the Javascript code I use, as requested in comments...
File models/person.js:
var personSchema = new mongoose.Schema({
key: String,
providerKey: String,
name: String,
phone: Number,
...
},
{
autoIndex: config.debug,
collection: 'persons'
});
personSchema.index({ providerKey: 1, key: 1 }, { unique: true });
module.exports = mongoose.model('Person', personSchema);
...
File controllers/person.js:
var _ = require('lodash')
var Person = require('../models/person');
...
var upsert = function(person, callback) {
Person.findOne(
{ providerKey: person.providerKey, key: person.key },
function(err, doc) {
if (err) {
log.warn('could not find person ', person.name, ':', err);
return callback(err);
}
if (doc) { // person did already exist
_.merge(doc, person);
} else { // person did not exist before
doc = new Person();
_.merge(doc, person);
}
doc.save(function(err) {
if (err) {
log.warn('could not save person ', doc.providerKey, ' ', doc.key, ':', err);
return callback(err);
}
callback(null);
});
}
);
};
...
var person = {};
person.phone = getParseNormalizePhoneAndReturn10DigitsStringOrNull();
upsert(person, function(err) {
...
});
Hope it helps...
UPDATE 2:
I am using node v0.12.7 and mongoose 4.1.12.
The first "number" that causes a cast error is "3932978***", while the biggest one not causing any error is "3927983***".
I must add that I did just notice in the person collection there are some 'floating point' numbers (when starting to populate the collection, the normalization function had probably some issues, and some dot had not been removed... So I have a couple of numbers like this: "320.2264***", if this could someway help...

updating embedded sub documents - mongoose

I have the following schemas:
var reviewSchema = new mongoose.Schema({
comments : String,
rating : String,
submitted_date: {type: Date, default: Date.now},
numAgreed : Number,
numDisagreed : Number
});
var userSchema = new mongoose.Schema({
firstName : String,
lastName : String,
numRatings : Number,
averageRating: Number,
reviews : [reviewSchema]
});
I am implementing an agree function (increment number of those who agreed with the review) for every review as follows:
exports.processAgree = function(req,res){
var firstName = req.body.firstName;
var lastName = req.body.lastName;
var index = req.body.index;
User.findOne({firstName:firstName,lastName:lastName}).lean().exec(function(err,user) {
if (err) {
throw err;
}
else{
user.reviews[index].numAgreed++;
user.markModified('reviews');
user.save(function (err) {
if (err) throw err;
});
}
});
};
However, I get the error:
reviewedUser.markModified('reviews');
^
TypeError: Object #<Object> has no method 'markModified'
I searched through stackoveflow and have seen responses to this issue but they don't to work in my case. E.g. There was a response at How to update an embedded document within an embedded document in mongoose?
The solution suggests to declare child schemas before the parent schemas which is the case in my situation.
Please let me know if more information is required to help.
Thanks.
As Johnny said, you should remove the call to lean method on Query.
Such that your code would look like
User.findOne({firstName:firstName,lastName:lastName}).exec(function(err,user) {
if (err) {
throw err;
}
else{
user.reviews[index].numAgreed++;
user.markModified('reviews');
user.save(function (err) {
if (err) throw err;
});
}
});
Lean is used to strip all the service methods and properties from objects that come from Mongoose methods. If you don't use lean method on Query object, Mongoose will return instances of Model. Mongoose doc on lean().
And markModified method, that you are looking for, resides in Mongoose Model instance. By the way, save is in Model instance too.

I can not get mongoose/node.js to retrieve data properly. What am I doing wrong?

I am trying to get node.js to write to the console the data in the table, my other tables work.
Whenever I try I get the following output:
NO ERROR!
QUERY:{"emitted":{"complete":[[]]},"_events":{}}
Am I missing something in the Schema definition?
Any help would be appreciated.
- Eric
The following is from the mongo shell :
> db.userAssessments.find({})
{ "accountId" : "509683edcb884b0000000001", "created" : ISODate("2013-01-12T03:31:20.723Z"), "_id" : ObjectId("50f0d9084469766bb7000001") }
This is my js:
var userAssessmentsSchema = new mongoose.Schema({
accountId : String,
created : Date,
id: String
});
ANALYZER.userAssessments = mongoose.model('userAssessments', userAssessmentsSchema);
ANALYZER.analyzeAssessment = function() {
var query = ANALYZER.userAssessments.find({}).exec(function(err, ass) {
if (!err) {
console.log("NO ERROR!");
console.log("QUERY:" + JSON.stringify(query));
} else {
console.log("ERROR!");
}
});
};
The result of the find query is passed to the exec callback as the second parameter (ass in your code). The return value you assign to query is the Promise object returned from exec.
UPDATE
Your other problem is that Mongoose pluralizes and lower-cases the model name to derive the collection name if you don't provide one. To make it use the userAssessments collection instead of userassessments you need to provide that collection name in the mongoose.model call.
So your code should be like this instead:
ANALYZER.userAssessments = mongoose.model(
'userAssessments', userAssessmentsSchema, 'userAssessments');
ANALYZER.analyzeAssessment = function() {
ANALYZER.userAssessments.find({}).exec(function(err, ass) {
if (!err) {
console.log("NO ERROR!");
console.log("QUERY:" + JSON.stringify(ass));
} else {
console.log("ERROR!");
}
});
};

Resources