Mongoose - is it possible to use parameters in mongo query? - node.js

I've found how to update in mongoose with this guide.
I want to increase a field, but the problem is: I want to get that field name in run-time.
in other words - I want to send type parameter and in runtime so it'll increase the relevant field (counter1 \ counter2).
is it possible??
var conditions = {_id:post},
update = { $inc: { counterType: 1 }},
options = {multi:false},
callback = function(err,numAffected){ if (err) console.log(err);}
Post.update(conditions,update,options,callback);
where Post is pre-defined as a Schema:
var Post = new Schema({
post : String,
user :String,
counter1:Number,
counter2:Number,
counterType:String
});
so if I call this function when counterType = counter1
the wanted result should be counter1 field incremented by 1 in the DB.
my problem is that it looks for "counterType" instead of the value in it (counter1)

Related

findByIdAndUpdate adding another document to the database rather than updating

I am using MEAN stack for patient CRUD operations. The update does not seem to be working properly. It adds another document to the database with the updated info but with a null id and leaves the old document that is supposed to be updated as is.
below is the code I wrote in the service for update patient
editPatient(id:string,patient: Patient){
const headers = { 'content-type': 'application/json'}
const body=patient;
console.log(body)
let url=environment.PATIENT_BASE_URL+environment.PATIENT.UPDATE_PATIENT + "?userId=" +id;
return this.httpClient.put(url, body);
}
Those are the contents of the environment file
export const environment = {
production: false,
BASE_URL:'http://localhost:3000',
PATIENT_BASE_URL:'http://localhost:3000/patients/',
PATIENT:{
GET_ALL_PATIENTS: 'list',
GET_PATIENT: 'view',
UPDATE_PATIENT: 'update',
DELETE_PATIENT: 'delete',
SEARCH_PATIENT: 'search',
ADD_PATIENT: 'add',
}
};
This is the code in patients.js
router.put('/update', function(req, res, next) {
const userId = req.body.userId;
let firstnameVal = req.body.firstName;
let lastnameVal = req.body.lastName;
let usernameVal = req.body.username;
let emailVal = req.body.email;
let birthDateVal = req.body.birthDate;
let genderVal = req.body.gender;
let patientObj = {
firstName: firstnameVal,
lastName: lastnameVal,
username: usernameVal,
email: emailVal,
birthDate : birthDateVal,
gender: genderVal
};
// patientsModel.update({'gender':'female'}, )
patientsModel.findByIdAndUpdate(userId, patientObj,{upsert: true, new: true} ,function(err, patientResponse){
if(err){
res.send({status:500, message: 'Unable to update the patient'});
}
else{
res.send({status:200, message: 'User updated successfully' ,results: patientResponse});
}
});
});
Because you used this option
upsert: true
If item with id not found it creates a new document
you can read the docs here
Using the upsert option, you can use findOneAndUpdate() as a
find-and-upsert operation. An upsert behaves like a normal
findOneAndUpdate() if it finds a document that matches filter. But, if
no document matches filter, MongoDB will insert one by combining
filter and update as shown below.
The second argument to findByIdAndUpdate is an update object. If it does not contain any update operators, it is treated as a replacement document.
If your intent is to replace the entire document so the only fields it contains are the ones provided in this function, add the _id to the object:
let patientObj = {
_id: new mongoose.types.ObjectId(userId),
firstName: firstnameVal,
...
If the intent is to modify the provided fields but leave any others fields alone, use the $set update operator like
patientsModel.findByIdAndUpdate(userId, {"$set": patientObj}, ...
There are a few problems with your code - as others have said:
the use of upsert: true is suspicious - I can't imagine when you'd want to upsert this, and
the lack of $set is also unusual unless the patientObj represents the entire document you wish to set
both these items are causing you issues, but I suspect your main problem is actually that your ID doesn't match anything.
You mention an auto-generated ID. Mongo uses an ObjectId (though mongoose perhaps does not) - depending on how you serialise this value, the string representation of it would probably look like this: 63b310df2b36d95e156a237d - however when you query for that value (as you do with userId) - it will return no matches, since you need to convert it to an object ID:
userId = new mongoose.types.ObjectId(req.body.userId)
You should also fix items 1 and 2 above.

Insert multiple document with mongoose

I made an API with express.js, and i use mongoDB for my database and mongoose as my ODM
I really confused when i want to insert multiple document to my collection in once post request.
Here my model :
const modul = require('../config/require');
const Schema = modul.mongoose.Schema;
let TeleponSchema = new Schema({
_pelanggan : {type: String},
telepon: {type: String, required: true}
});
module.exports = modul.mongoose.model('telepon', TeleponSchema, 'telepon');
and here my controller
const Telepon = require('../models/telepon.model')
exports.create = (req,res) => {
let telepon = new Telepon({
_pelanggan : req.body.pel,
telepon: req.body.telepon
});
telepon.save((err,data) => {
if(err){
res.send({message:'eror', detail: err});
}else{
res.send({message:'success', data: data})
}
});
}
Then i post my request with postman like this :
but the result in my document is :
that's the problem, the value of 'telepon' is in the same row and separated by comma instead of insert a new row and create a new _id
i want the result of my collection like this :
(example)
Any help and suggestion would be much appreciated
Thank you!
1) Per .save call you will only affect one document, check out insertMany to do multiple.
2) req.body.telepon is either an array of numbers, or is already just the comma delimited list of numbers; if it is an array the .toString will result in a comma delimited list anyways. So when you new up the Telepon it has both values in one property, which is what you see in the result.

find id of latest subdocument inserted in mongoose

i have a model schema as :
var A = new Schema ({
a: String,
b : [ { ba: Integer, bb: String } ]
}, { collection: 'a' } );
then
var M = mongoose.model("a", A);
var saveid = null;
var m = new M({a:"Hello"});
m.save(function(err,model){
saveid = model.id;
}); // say m get the id as "1"
then
m['b'].push({ba:235,bb:"World"});
m.save(function(err,model){
console.log(model.id); //this will print 1, that is the id of the main Document only.
//here i want to find the id of the subdocument i have just created by push
});
So my question is how to find the id of the subdocument just pushed in one field of the model.
I've been looking for this answer as well, and I'm not sure that I like accessing the last document of the array. I do have an alternative solution, however. The method m['b'].push will return an integer, 1 or 0 - I'm assuming that is based off the success of the push (in terms of validation). However, in order to get access to the subdocument, and particularly the _id of the subdocument - you should use the create method first, then push.
The code is as follows:
var subdoc = m['b'].create({ ba: 234, bb: "World" });
m['b'].push(subdoc);
console.log(subdoc._id);
m.save(function(err, model) { console.log(arguments); });
What is happening is that when you pass in the object to either the push or the create method, the Schema cast occurs immediately (including things like validation and type casting) - this means that this is the time that the ObjectId is created; not when the model is saved back to Mongo. In fact, mongo does not automatically assign _id values to subdocuments this is a mongoose feature. Mongoose create is documented here: create docs
You should also note therefore, that even though you have a subdocument _id - it is not yet in Mongo until you save it, so be weary of any DOCRef action that you might take.
The question is "a bit" old, but what I do in this kind of situation is generate the subdocument's id before inserting it.
var subDocument = {
_id: mongoose.Types.ObjectId(),
ba:235,
bb:"World"
};
m['b'].push(subDocument);
m.save(function(err,model){
// I already know the id!
console.log(subDocument._id);
});
This way, even if there are other database operations between the save and the callback, it won't affect the id already created.
Mongoose will automatically create an _id for each new sub document, but - as far as I know - doesn't return this when you save it.
So you need to get it manually. The save method will return the saved document, including the subdocs. As you're using push you know it will be the last item in the array, so you can access it from there.
Something like this should do the trick.
m['b'].push({ba:235,bb:"World"});
m.save(function(err,model){
// model.b is the array of sub documents
console.log(model.b[model.b.length-1].id);
});
If you have a separate schema for your subdocument, then you can create the new subdocument from a model before you push it on to your parent document and it will have an ID:
var bSchema = new mongoose.Schema({
ba: Integer,
bb: String
};
var a = new mongoose.Schema({
a: String,
b : [ bSchema ]
});
var bModel = mongoose.model('b', bSchema);
var subdoc = new bModel({
ba: 5,
bb: "hello"
});
console.log(subdoc._id); // Voila!
Later you can add it to your parent document:
m['b'].push(subdoc)
m.save(...

Mongoose embedded documents / DocumentsArrays id

In the Mongoose documentation at the following address:
http://mongoosejs.com/docs/embedded-documents.html
There is a statement:
DocumentArrays have an special method id that filters your embedded
documents by their _id property (each embedded document gets one):
Consider the following snippet:
post.comments.id(my_id).remove();
post.save(function (err) {
// embedded comment with id `my_id` removed!
});
I've looked at the data and there are no _ids for the embedded documents as would appear to be confirmed by this post:
How to return the last push() embedded document
My question is:
Is the documentation correct? If so then how do I find out what 'my_id' is (in the example) to do a '.id(my_id)' in the first place?
If the documentation is incorrect is it safe to use the index as an id within the document array or should I generate a unique Id manually (as per the mentioned post).
Instead of doing push() with a json object like this (the way the mongoose docs suggest):
// create a comment
post.comments.push({ title: 'My comment' });
You should create an actual instance of your embedded object and push() that instead. Then you can grab the _id field from it directly, because mongoose sets it when the object is instantiated. Here's a full example:
var mongoose = require('mongoose')
var Schema = mongoose.Schema
var ObjectId = Schema.ObjectId
mongoose.connect('mongodb://localhost/testjs');
var Comment = new Schema({
title : String
, body : String
, date : Date
});
var BlogPost = new Schema({
author : ObjectId
, title : String
, body : String
, date : Date
, comments : [Comment]
, meta : {
votes : Number
, favs : Number
}
});
mongoose.model('Comment', Comment);
mongoose.model('BlogPost', BlogPost);
var BlogPost = mongoose.model('BlogPost');
var CommentModel = mongoose.model('Comment')
var post = new BlogPost();
// create a comment
var mycomment = new CommentModel();
mycomment.title = "blah"
console.log(mycomment._id) // <<<< This is what you're looking for
post.comments.push(mycomment);
post.save(function (err) {
if (!err) console.log('Success!');
})

Increasing one field in a MongoDB collection with Mongoose

I'm trying to increment a value in a collection in my MongoDB database through Mongoose. This is the demo code shown on the Mongoose website:
var conditions = { name: 'borne' }
, update = { $inc: { visits: 1 }}
, options = { multi: true };
Model.update(conditions, update, options, callback)
And I have something like this:
var conditions = { "uniqueId" : itemId };
var update;
if(increase)
update = {$inc : {inStock : 1}};
else
update = {$dec : {inStock : 1}};
Item.update(conditions, update, {}, callback);
As you can see there is not much difference from the Mongoose's website code.
The problem is that when this piece of code is executed, I end up having in my collection one field called $dec (or $inc) which has an object as a field in the form {inStock : 1}. I just would like to increment the inStock entry of the collection. In the Schema I have:
var ItemToSell = new Schema({
uniqueId : { type: Number, index: true }
, name : String
, type : String
, inStock : Number
});
Can anyone point out what am I doing wrong?
Thanks a lot.
A) Make sure you're Mongoose is up-to-date. Older versions were very buggy on Model.update operations because Mongoose attempts to infer when you are merely passing a new object, in which case it turns your update object into a $set operation.
B) Try removing the empty {} from your function call. It is optional, and by passing an empty object rather than actual options, you may be confusing Mongoose into setting the { safe: false } option, which could also be causing your problem. I have not checked the source code to confirm that that could be the issue, but it's probably worth a try.

Resources