Add "where" query in Sequalize based on flag - angularjs

I want to add "where" query in Sequalize based on flag . Let me know how to get this.
For example if the flag is true then I want to add this "where" class otherwise I don't want to add the "where" clause.
models.Users.findAll({
where: {
email: req.query.email
}
}).then(function (list) {
res.send(list);
}).catch(function (error) {
res.status(500).json(error);
});
models.Users.findAll({
}).then(function (list) {
res.send(list);
}).catch(function (error) {
res.status(500).json(error);
});

You can create JSON first which you are providing in where clause and then pass it in where clause.. something like
var jsonObj = null ;
if (req.query.email){
jsonObj = {"email": req.query.email};
} else {
jsonObj = {"email": {$ne:null}}; //otherwise it will return all rows, if email is not null in your database
}
models.Users.findAll({
where: jsonObj
}).then(function (list) {
res.send(list);
}).catch(function (error) {
res.status(500).json(error);
});
Hope this will help

You can start with an empty query object, and add a where property to it when appropriate:
let query = {};
if (someCondition) {
query.where = { email: req.query.email };
}
models.Users.findAll(query).then(...);

You can use simple one-line if statement inside the findAll method call. Let's assume that variable is your boolean flag
models.Users.findAll(variable ? { where: { email: req.query.email } } : {}).then(list => {
res.send(list);
}).catch(error => {
res.status(500).json(error);
});
Or you can assign the options object to a variable and use the same if statement, but outside the findAll call
let options = variable ? { where: { email: req.query.email } } : {};
models.Users.findAll(options).then(list => {
// ...
});

Related

findOneAndUpdate causing duplication problem

I am having a problem in findOneAndUpdate in mongoose.
The case is that i am updating a document by finding it.
The query is as follows:
UserModel.findOneAndUpdate({
individualId: 'some id'
}, {
$push: {
supporterOf: 'some string'
}
})
The 'supporterOf' is the ref of UserModel and its type is 'ObjectId'.
The issue i am facing here is that, 'some string' is being pushed twice under 'supporterOf' in the document.
Can anyone tell me that how to push an array element inside the document?
I was having same problem, solution is.
I was keeping await like below.
**await** schema.findOneAndUpdate(queryParms, {
"$push": {
"array1": arrayDetails,
"array2": array2Details
}
}, {
"upsert": true,
"new": true
},
function (error, updateResponse) {
if (error) {
throw new Error (error);
} else {
// do something with updateResponse;
}
});
simply removing await helped me resolving this problem.
Need to find the root cause.
any pointer for references are welcome.
I have recently encountered the same problem. However, I managed to overcome this issue by some other logics (details given below) but couldn't understand the reason behind that why findOneAndUpdate inserting duplicate entries in mongodb.
You can overcome this problem by following logic.
Use findOne or findById instead of findOneAndUpdate to search the document in your collection and then manually update your document and run save().
You can have better idea with this code snippet
return new Promise(function (resolve, reject) {
Model.findOne({
someCondition...
}, function (err, item) {
if (err) {
reject(err);
} else {
item.someArray.push({
someKeyValue...
});
item.save().then((result) => {
resolve(result)
}).catch((err) => {
reject(err)
});
}
}).catch((err) => {
reject(err)
});
});
This will not insert duplicate item. However, if you come to know the reasoning behind duplication, must do update this thread.
The issue seems to stem from combining an await and a callback. I had the same issue until I realised I was using an (err, resp) callback and a .catch(...).
models[auxType].findOneAndUpdate(
filter,
updateObject,
options,
(err, resp)=>{
if (err) {
console.log("Update failed:",err)
res.json(err)
} else if (resp) {
console.log("Update succeeded:",resp)
res.json(resp)
} else {
console.log("No error or response returned by server")
}
})
.catch((e)=>{console.log("Error saving Aux Edit:",e)}); // << THE PROBLEM WAS HERE!!
The problem resolved as soon as I removed the .catch(...) line.
From the mongoose documentation:
"Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. However, unlike promises, calling a query's .then() can execute the query multiple times."
(https://mongoosejs.com/docs/queries.html#queries-are-not-promises)
Use $addToSet instead of $push, it should solve the problem. I believe there is an issue with the data structure used in the creation of a mongoose 'Model'. As we know push is an array (which allows duplication) operation while addToSet may be a Set operation (Sets do not allow duplication).
The problem with the accepted answer is that it only solves the problem by wrapping it in an unnecessary additional promise, when the findOneAndUpdate() method already returns a promise. Additionally, it uses both promises AND callbacks, which is something you should almost never do.
Instead, I would take the following approach:
I generally like to keep my update query logic separate from other concerns for both readability and re-usability. so I would make a wrapper function kind of like:
const update = (id, updateObj) => {
const options = {
new: true,
upsert: true
}
return model.findOneAndUpdate({_id: id}, {...updateObj}, options).exec()
}
This function could then be reused throughout my application, saving me from having to rewrite repetitive options setup or exec calls.
Then I would have some other function that is responsible for calling my query, passing values to it, and handling what comes back from it.
Something kind of like:
const makePush = async () => {
try {
const result = await update('someObjectId', {$push: {someField: value}});
// do whatever you want to do with the updated document
catch (e) {
handleError(e)
}
}
No need to create unnecessary promises, no callback hell, no duplicate requests, and stronger adherence to single responsibility principles.
I was having the same problem. My code was:
const doc = await model.findOneAndUpdate(
{filter}, {update},
{new: true}, (err, item) => if(err) console.log(err) }
)
res.locals.doc = doc
next();
The thing is, for some reason this callback after the "new" option was creating a double entry. I removed the callback and it worked.
I had the same problem.
I found a solution for me:
I used a callback and a promise (so using keyword "await") simultaneously.
Using a callback and a promise simultaneously will result in the query being executed twice. You should be using one or the other, but not both.
options = {
upsert: true // creates the object if it doesn't exist. defaults to false.
};
await Company.findByIdAndUpdate(company._id,
{ $push: { employees: savedEmployees } },
options,
(err) => {
if (err) {
debug(err);
}
}
).exec();
to
options = {
upsert: true // creates the object if it doesn't exist. defaults to false.
};
await Company.findByIdAndUpdate(company._id,
{ $push: { employees: savedEmployees } },
options
).exec();
UserModel.findOneAndUpdate(
{ _id: id },
{ object }
)
Even if you use _id as a parameter don't forget to make the filter explicit by id
In my case, changing the async callback solved the problem.
changing this:
await schema.findOneAndUpdate(
{ queryData },
{ updateData },
{ upsert: true },
(err) => {
if (err) console.log(err);
else await asyncFunction();
}
);
To this:
await schema.findOneAndUpdate(
{ queryData },
{ updateData },
{ upsert: true },
(err) => {
if (err) console.log(err);
}
);
if (success) await asyncFunction();
The $addToSet instead of $push allowed me to prevent duplicate entry in my mongoDb array field of User document like this.
const blockUserServiceFunc = async(req, res) => {
let filter = {
_id : req.body.userId
}
let update = { $addToSet: { blockedUserIds: req.body.blockUserId } };
await User.findOneAndUpdate(filter, update, (err, user) => {
if (err) {
res.json({
status: 501,
success: false,
message: messages.FAILURE.SWW
});
} else {
res.json({
status: 200,
success: true,
message: messages.SUCCESS.USER.BLOCKED,
data: {
'id': user._id,
'firstName': user.firstName,
'lastName': user.lastName,
'email': user.email,
'isActive': user.isActive,
'isDeleted': user.isDeleted,
'deletedAt': user.deletedAt,
'mobileNo': user.mobileNo,
'userName': user.userName,
'dob': user.dob,
'role': user.role,
'reasonForDeleting': user.reasonForDeleting,
'blockedUserIds': user.blockedUserIds,
'accountType': user.accountType
}
});
}
}
).catch(err => {
res.json({
status: 500,
success: false,
message: err
});
});
}

update all values in the sub array of one object in mongodb using mongoose

user = {
'userid':'111',
'mail':[{
'time':22222,
'info':'this is a info1',
'read':false,
},{
'time':33333,
'info':'this is a info2',
'read':false,
}]
}
then, I want to change one user's read flag to true, how can i do for it ?
here is my answer:
User.update({
'userid':userid,
'mails':{
'$elemMatch':{
'read':false
}
}
},{
'$set':{
'mail.$.read':false,
'newmail':0,
}
}, { multi: true }, function (err, data) {
if(err > 0){
console.log('ReadMail err', err);
}
});
here is a simple example: my model is User !! my url is the path to the DB
var newUser = new User();
newUser.name = request.body.name;
newUser.email = request.body.email;
newUser.pass = request.body.pass;
newUser.position = request.body.pos;
newUser.phone = request.body.phone;
mongoose.connection.openUri(url);
var myquery = { _id : request.params._id };
console.log("updating...")
User.findByIdAndUpdate(myquery,{$set: newUser},{new: true},function(err, result) {
if(err)
{
throw err;
}
response.json({code: 0 , result});
});

Can't compare MongoDB data with javascript array

I want to compare the data which I got from Mongo to javascript array. I am using lodash to compare. But it always return incorrect result.
var editUser = function(userData, getOutFunction) {
var status = CONSTANTS.NG;
checkExistUser(userData._id).then(function(user) {
if (user !== null) {
var userGroup = JSON.stringify(user.group);
user.group = user.group.map((groupId) => {
return groupId.toString();
});
var removedGroups = _.difference(userGroup, userData.group);
var addedGroups = _.difference(userData.group, userGroup);
console.log('Removed Groups: ', removedGroups);
console.log('Added Groups: ', addedGroups);
} else {
status = CONSTANTS.NG;
logger.debug(DEBUG_CLASS_NAME, "Cannot find object");
if (typeof(getOutFunction) !== 'undefined') {
getOutFunction(status, null);
} else {
NO_CALLBACK();
}
}
}).catch(function() {
console.log('Promise is error');
});
var checkExistUser = function(userId) {
return new Promise(function(resolve, reject) {
UserDAO.findById(userId, function(err, user) {
if (err) {
logger.debug(DEBUG_CLASS_NAME, {
name: err.name,
code: err.code,
message: err.message,
method: "checkExist"
});
resolve(null);
} else {
resolve(user);
}
});
});
}
For example:When I try to input value for lodash difference function
var user.group = ["58b8da67d585113517fed34e","58b8da6ed585113517fed34f"];
var userData.group = [ '58b8da67d585113517fed34e' ];
I want lodash difference return below result:
Removed Groups: ['58b8da6ed585113517fed34f']
Added Groups: []
However, the function gave me the result like:
Removed Groups: []
Added Groups: [ '58b8da67d585113517fed34e' ]
Can anyone help me in this case?
I will do appreciate it.
I have had this issue as well, the result from mongodb is an ObjectId type so you can compare the someObjectId.toString() value with your array of strings, or you could use
someObjectId.equals(stringOrObjectIdValue)
However, if you want to keep using lodash functions you will either have to force both arrays to strings or to ObjectIds before passing them into the function.

MongoDB: how can I find and merge array

I'm trying to find a specific ID in my document and then merge an array to the existing one, for example if I have this array stored in db.friends:
["12","13","14"]
and I send this array: ["12","16","18"], db.friends should contain: ["12","13","14","16","18"]
I'm using underscore library, but I'm not sure I have to (maybe "aggregate" in mongoose?)
Here is what I did, can you tell me where am I wrong?
function saveFollowers(req, res) {
var friends = req.body.friends; // the new array to merge ["54aafe9df4ee360300fc94c7"];
User.findOne({_id: req.user._id}).exec(function (err, user) {
if (err) {
res.jsonp({error: "Error fetching user info"})
} else {
friends = _.extend(friends, user.friends); //user.friends=existing friends we have in db
user.save(function (err) {
if (err) { res.jsonp({error: "Cant save"}); }
console.log("Friends NOW:"+JSON.stringify(friends)); //Here I don't see the merge, also, I can't see it in mongo db.
res.jsonp("success");
});
}
});
Thank you!
With your current implementation, you haven't actually modified the friends key in the returned user object. So rather you can use the union method as
user.friends = _.union(friends, user.friends); //user.friends=existing friends
user.save(function (err) { .. }
Or with ES6 using the spread operator for concatenating the array and Set for creating a distinct set of elements:
user.friends = [...new Set([...friends ,...user.friends])];
user.save(function (err) { .. }
Another alternative is using the aggregation framework, you could utilize the $setUnion operator:
function saveFollowers(req, res) {
var friends = req.body.friends; // the new array to merge ["54aafe9df4ee360300fc94c7"];
User.aggregate([
{ "$match": { _id: req.user._id } },
{
"$project": {
"friends": { "$setUnion": [ "$friends", friends ] }
}
}
]).exec(function (err, results){
if (err) {
res.jsonp({error: "Error fetching user info"})
} else {
User.findByIdAndUpdate(req.user._id,
{ "$set": { "friends": results[0].friends } },
{ "new": true },
function (err, user) {
if (err) { res.jsonp({error: "Cant save"}); }
console.log("Friends NOW: "+ JSON.stringify(user.friends));
res.jsonp("success");
}
);
}
});
}

Sequentially ngresource calls

I have a controller making two $resource calls against two REST services where the result of the first one is used as input by the second one.
Here the code:
if (requestLock == false) {
$scope.T_01_04_sharedData.tempRequestForT_01_04 = insertNewRequest("aggr_1", $rootScope.globals.currentUser.username, "", "temp", "2016-07-30 00:00:00");
requestLock = true;
}
if (action == 'add') {
updateSelectedForRequest(prosumer, 'selected', $rootScope.globals.currentUser.username, $scope.T_01_04_sharedData.tempRequestForT_01_04);
} else {
updateSelectedForRequest(prosumer, 'non-selected', $rootScope.globals.currentUser.username, $scope.T_01_04_sharedData.tempRequestForT_01_04);
}
Function updateSelectedForRequest
function updateSelectedForRequest(username, status, businessUser, request) {
WidgetService.T_01_04_updateSelectedForRequest.query({
businessUser_id: businessUser,
request_id: request,
username: username,
status: status
}, function (result) {
// response handler
});
}
Function insertNewRequest
function insertNewRequest(bu_id_target, requester, description, status, validUntil) {
return WidgetService.T_01_04_insertNewRequest.query({
bu_id_target: bu_id_target,
requester: requester,
description: description,
status: status,
validUntil: validUntil
}, function (result) {
$scope.T_01_04_sharedData.tempRequestForT_01_04 = result.request_id;
return result;
});
}
The error is that the first call is not resolved sequentially so the second one has no input.
Is there the possibility to run these two calls sequentially in order to wait for the second call the input from the first one?
Thanks a lot.
I'm not familiar with ngresource, but you can try something like this.
if (requestLock == false) {
insertNewRequest("aggr_1", $rootScope.globals.currentUser.username, "", "temp", "2016-07-30 00:00:00")
.then(function(result){
$scope.T_01_04_sharedData.tempRequestForT_01_04 = result;
if (action == 'add') {
updateSelectedForRequest(prosumer, 'selected', $rootScope.globals.currentUser.username, $scope.T_01_04_sharedData.tempRequestForT_01_04);
} else {
updateSelectedForRequest(prosumer, 'non-selected', $rootScope.globals.currentUser.username, $scope.T_01_04_sharedData.tempRequestForT_01_04);
}
}, function(error){/* manage error here */});
requestLock = true;
}
function insertNewRequest(bu_id_target, requester, description, status, validUntil) {
return new Promise(function(resolve, reject){
PromiseWidgetService.T_01_04_insertNewRequest.query({
bu_id_target: bu_id_target,
requester: requester,
description: description,
status: status,
validUntil: validUntil
}, function (result) {
$scope.T_01_04_sharedData.tempRequestForT_01_04 = result.request_id;
resolve(result);
});
})
}
more information on promise here : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Resources