Calling stored procedures in Sequelize.js - node.js

I have searched documentation and tried google that, but I did not find a straight answer to the question:
How can I call a stored procedure in Sequelize?
I have searched the documentation of Sequelize but I have even not found a trace of the word "procedure" in that.
The closest I got was this bug-report-turned-feature-request:
https://github.com/sequelize/sequelize/issues/959
Quoting from the link:
What I imagine would be awesome:
sequelize.query('CALL calculateFees();').success(
function (settingName1, settingName2, settingName3, users) {
});
They mention that it is possible to call stored procedures, but the syntax is not provided.
Can anyone give me an example with the proper syntax?
Thanks.

Call SP with parameters in Sequelize
sequelize
.query('CALL login (:email, :pwd, :device)',
{replacements: { email: "me#jsbot.io", pwd: 'pwd', device: 'android', }})
.then(v=>console.log(v));

Change success to spread and you're good to go. Note that this will only work on sequlize 2.0

sequalise queries return promises so below is how i query stored procedures.
sequelize.query('CALL calculateFees();').then(function(response){
res.json(response);
}).error(function(err){
res.json(err);
});

I am sure, you may also need to get output from stored procedure. Here is a code including output value from procedure, using sequelize:
models.sequelize.query('DECLARE #outParam1 INT, #outParam2 INT EXEC procedureName #param1=:param, #outParam1 = #outParam1 output, #outParam2 = #outParam2 output SELECT #outParam1 AS "outParam1", #outParam2 AS "outParam2"',
{
replacements:
{
param: 123
},
type: models.sequelize.QueryTypes.EXEC
}).spread(result => {
if (result)
{
console.log("\nInside result : " + JSON.stringify(result));
//return response here
}

For a MSSQL stored procedure accepting two DATETIME parameters, this worked for me:
db.query('EXEC STORED_PROCEDURE_NAME :startDate, :endDate',
{ replacements: { startDate: moment(payload.startDate).format('YYYY-MM-DD HH:mm:ss'), endDate: moment(payload.endDate).format('YYYY-MM-DD HH:mm:ss')},
raw: true }
)

I executed the stored procedure with the EXEC Key word.
sequelize
.query('EXEC getData :#param1', { replacements: { #param1: 'Test'}, type:sequelize.QueryTypes.SELECT })
.then(data => /*Do something with the data*/)
.catch(error => /*Do something with the error*/)

Call SP with multiple parameters in Sequelize
I am using await also.
const existing = await db.sequelize.query(`exec Fetch_Details ${AlphaCode},${Id}`, { type: QueryTypes.SELECT });
if (existing.length>=0) {
res.send({
status: "OK",
message: "Records found!",
result: existing,
});
}
else{
res.send({
status: 404,
message: "Not Found!"
});
}

Related

Cannot read property 'columnName' of undefined in sails Js Mongo DB

I am using sails JS with Mongo DB.
My model is:
module.exports = {
attributes: {
title:{type:"string",required:true},
content:{type:"string",required:true},
date:{type:"string",required:true},
filename:{type:"string",required:true},
},
};
My Controller is:
fetchposts:function(req,res){
console.log("in fetch posts")
mysort={$id:-1}
Cyberblog.find().sort(mysort).limit(5).exec(function(err, result) {
if (err || !result) {
message="no records fetched";
console.log(message);
res.redirect('/newpost');
}
else{
console.log(result)
}
I am facing an error saying that
"Warning: The sort clause in the provided criteria is specified as a dictionary (plain JS object),
meaning that it is presumably using Mongo-Esque semantics (something like { fullName: -1, rank: 1 }).
But as of Sails v1/Waterline 0.13, this is no longer the recommended usage. Instead, please use either
a string like 'fullName DESC', or an array-like [ { fullName: 'DESC' } ].
(Since I get what you mean, tolerating & remapping this usage for now...)
and I am unable to fetch any records. It is showing no records fetched.
So I have one warning on Sort and no records coming from DB. Please help me resolve the issue.
Sort clause allow send string:
var users = await User.find({ name: 'Jake'})
.sort('age ASC');
return res.json(users);
Or an array:
var users = await User.find({ name: 'Finn'})
.sort([
{ age: 'ASC' },
{ createdAt: 'ASC' },
]);
return res.json(users);
Check this out in the documentation:
https://sailsjs.com/documentation/reference/waterline-orm/queries/sort

Mongodb/mongoose omit a field in response [duplicate]

I have a NodeJS application with Mongoose ODM(Mongoose 3.3.1). I want to retrieve all fields except 1 from my collection.For Example: I have a collection Product Which have 6 fields,I want to select all except a field "Image" . I used "exclude" method, but got error..
This was my code.
var Query = models.Product.find();
Query.exclude('title Image');
if (req.params.id) {
Query.where('_id', req.params.id);
}
Query.exec(function (err, product) {
if (!err) {
return res.send({ 'statusCode': 200, 'statusText': 'OK', 'data': product });
} else {
return res.send(500);
}
});
But this returns error
Express
500 TypeError: Object #<Query> has no method 'exclude'.........
Also I tried, var Query = models.Product.find().exclude('title','Image'); and var Query = models.Product.find({}).exclude('title','Image'); But getting the same error. How to exclude one/(two) particular fields from a collection in Mongoose.
Use query.select for field selection in the current (3.x) Mongoose builds.
Prefix a field name you want to exclude with a -; so in your case:
Query.select('-Image');
Quick aside: in JavaScript, variables starting with a capital letter should be reserved for constructor functions. So consider renaming Query as query in your code.
I don't know where you read about that .exclude function, because I can't find it in any documentation.
But you can exclude fields by using the second parameter of the find method.
Here is an example from the official documentation:
db.inventory.find( { type: 'food' }, { type:0 } )
This operation returns all documents where the value of the type field is food, but does not include the type field in the output.
Model.findOne({ _id: Your Id}, { password: 0, name: 0 }, function(err, user){
// put your code
});
this code worked in my project. Thanks!! have a nice day.
You could do this
const products = await Product.find().select(['-image'])
I am use this with async await
async (req, res) => {
try {
await User.findById(req.user,'name email',(err, user) => {
if(err || !user){
return res.status(404)
} else {
return res.status(200).json({
user,
});
}
});
} catch (error) {
console.log(error);
}
In the updated version of Mongoose you can use it in this way as below to get selected fields.
user.findById({_id: req.body.id}, 'username phno address').then(response => {
res.status(200).json({
result: true,
details: response
});
}).catch(err => {
res.status(500).json({ result: false });
});
I'm working on a feature. I store a userId array name "collectedUser" than who is collected the project. And I just want to return a field "isCollected" instead of "collectedUsers". So select is not what I want. But I got this solution.
This is after I get projects from database, I add "isCollected".
for (const item of projects) {
item.set("isCollected", item.collectedUsers.includes(userId), {
strict: false,
})
}
And this is in Decorator #Schema
#Schema({
timestamps: true,
toObject: {
virtuals: true,
versionKey: false,
transform: (doc, ret, options): Partial<Project> => {
return {
...ret,
projectManagers: undefined,
projectMembers: undefined,
collectedUsers: undefined
}
}
}
})
Finally in my controller
projects = projects.map(i => i.toObject())
It's a strange tricks that set undefined, but it really work.
Btw I'm using nestjs.
You can do it like this
const products = await Product.find().select({
"image": 0
});
For anyone looking for a way to always omit a field - more like a global option rather than doing so in the query e.g. a password field, using a getter that returns undefined also works
{
password: {
type: String,
required: true,
get: () => undefined,
},
}
NB: Getters must be enabled with option { toObject: { getters:true } }
you can exclude the field from the schema definition
by adding the attribute
excludedField : {
...
select: false,
...
}
whenever you want to add it to your result,
add this to your find()
find().select('+excludedFiled')

Creating unique index via mongodb native driver

There is a code:
const { MongoClient } = require('mongodb')
const db = MongoClient.connect('mongodb://172.17.0.2:27017/test')
db
.then(
async dataBase => {
eduDb = dataBase.db('edu-service-accounts')
const accounts = eduDb.collection('accounts')
await accounts.createIndex({ email: 1 }, { unique: true })
accounts.insertOne({ email: '123' })
}
)
Code above creates an index, but that is no unique. I already read official docs for native mongoDB driver, but can't handle it.
And yes, I've deleted all old indexex before testing that code.
Can someone please show a code that really create an index with unique.
I mean not part of official doc, or something like that - I need code that works.
NOTE: I tested that code with local db and mlab - the same result.
Like the documentation says: db.createIndex(collectionname, index[, options], callback) the creation returns an index. Try to log the result of the callback. Maybe you are getting an error from the db.
Try something like:
// your connection stuff
accounts.createIndex({ email: 1 }, { unique: true }, function(err, result) {
if(err) {
console.log(err);
} else {
console.log(result);
}
});
After that please provide us the logs.

Update data in MongoDB with Mongojs using findAndModify()

Yet another first-timer problem here. This gets data from a database and displays it in some text fields (that part is not shown in the code below) and after the user edits it the data should be updated in the database via the findAndModify() method and I think this is where the issue lies. There are no errors, it just doesn't do anything. EDIT The following error is received: MongoError: Either an update or remove=true must be specified
server.js
MongoClient.connect("mongodb://user:secretPassword#aws-us-east-1-portal.7.dblayer.com:10712,aws-us-east-1-portal.10.dblayer.com:10316/database", function(err, db) {
if (err) throw err;
var contactList = db.collection("contactList");
app.put('/contactList/:id', function(req, res) {
var id = req.params.id;
console.log("edited: " + req.body.name); //works up until here
contactList.findAndModify({
query: {_id: mongojs.ObjectId(id)},
update: {$set: {name: req.body.name, email: req.body.email, number: req.body.number}},
new: true
}, function (err, doc) {
res.json(doc);
})
});
controller.js
$scope.update = function() {
$http.put('/contactList/' + $scope.contact._id, $scope.contact).success(function(response) {
refresh();
})
};
If this were me I would first do a couple of things:
Before your call to findAndModify just do a simple find using your query. Make sure you can actually find the object using your query. If that works you know that the 'find' part of the findAndModify is probably ok.
Do some console logging inside the callback handler of the findAndModify call. As it stands you do not do anything if an err is returned from the findAndModify call. It is possible your call is returning an error that you are just ignoring and it may provide some additional insight into your problem.
I would try these two first and see if it helps.
Update:
Example using native:
collection.findAndModify(
{ field: 'some value' },
[],
{ $set: { field2: 'some new value' } },
{ new:true },
function(err, doc) {
//handle err and doc
});

Node.js + mongoose [RangeError: Maximum call stack size exceeded]

I am new to Node.js and I'm facing an error :
RangeError: Maximum call stack size exceeded
I'm not able able to solve the problem because most of the stack problems in others stackoverflow questions about Node.js deals with hundreds of callback but I have only 3 here.
First a fetch (findById) then an update an later a save operation!
My code is :
app.post('/poker/tables/:id/join', function(req, res) {
var id = req.params.id;
models.Table.findById(id, function(err, table) {
if (err) {
console.log(err);
res.send({
message: 'error'
});
return;
}
if (table.players.length >= table.maxPlayers) {
res.send({
message: "error: Can't join ! the Table is full"
});
return;
}
console.log('Table isnt Full');
var BuyIn = table.minBuyIn;
if (req.user.money < table.maxPlayers) {
res.send({
message: "error: Can't join ! Tou have not enough money"
});
return;
}
console.log('User has enought money');
models.User.update({
_id: req.user._id
}, {
$inc: {
money: -BuyIn
}
}, function(err, numAffected) {
if (err) {
console.log(err);
res.send({
message: 'error: Cant update your account'
});
return;
}
console.log('User money updated');
table.players.push({
userId: req.user._id,
username: req.user.username,
chips: BuyIn,
cards: {}
});
table.save(function(err) {
if (err) {
console.log(err);
res.send({
message: 'error'
});
return;
}
console.log('Table Successfully saved with new player!');
res.send({
message: 'success',
table: table
});
});
});
});
});
The error occurs during the save operation at the end!
I use MongoDb with mongoose so Table and User are my database collections.
This is from my first project with Node.js,Express.js and MongoDB so I probably have made huge mistakes in the async code :(
EDIT: I tried to replace the save with an update:
models.Table.update({
_id: table._id
}, {
'$push': {
players: {
userId: req.user._id,
username: req.user.username,
chips: BuyIn,
cards: {}
}
}
}, function(err, numAffected) {
if (err) {
console.log(err);
res.send({
message: 'error'
});
return;
}
console.log('Table Successfully saved with new player!');
res.send({
message: 'success',
table: table
});
});
But it doesn't help the error is still coming and I don't know how to debug it :/
I've been passing for this problem too.
Basically, when you have a property with a ref, and you want to use it in a find, for example, you can't pass the whole document.
For example:
Model.find().where( "property", OtherModelInstance );
this will trigger that error.
However, you have 2 ways to fix this for now:
Model.find().where( "property", OtherModelInstance._id );
// or
Model.find().where( "property", OtherModelInstance.toObject() );
This may stop your problems for now.
There is a issue in their GitHub repo where I reported this, however it's without fix for now. See the issue here.
I kept getting this error and finally figured it out. It's very hard to debug since no real information is presented in the error.
Turns out I was trying to save an object into a field. Saving only a specific property of the object, or JSON stringifying it, worked like a charm.
Seems like it would be nice if the driver gave a more specific error, but oh well.
MyModel.collection.insert causes:
[RangeError: Maximum call stack size exceeded]
When you pass array of instances of MyModel instead of just array with values of that objects.
RangeError:
let myArray = [];
myArray.push( new MyModel({ prop1: true, prop2: false }) );
MyModel.collection.insert(myArray, callback);
No error:
let myArray = [];
myArray.push( { prop1: true, prop2: false } );
MyModel.collection.insert(myArray, callback);
There are a few ways to debug nodejs applications
Built-in Debugger
The Node.js debugger is documented here: http://nodejs.org/api/debugger.html
To place breakpoints, simply put debugger; at the place you want to break. As you said the table.save callback is giving you troubles, you could put a breakpoint inside that function.
Then you run node with the debugger enabled:
node debug myscript.js
And you will get more helpful output.
Investigating the stack
You can also use console.trace to print a stacktrace, if you have a good idea of when/where you run into problems, and want to figure out how you got there.
Good luck, I hope this helps!

Resources