Build Mongo Query based on query parameters in url - node.js

I want to build a query as per the value available in the query parameters of the URL. The sample URL is :-
http://localhost:3000/api/user?page=&status=&search&role_id=
So when the status is available, the where clause related to it should work, the same for search and role_id.
I have tried to built a query where pagination part along with search parameter is working perfectly. But when I pass/set the keys of
query string, the query shows no results.
The query I have build so far is something like this:-
let {page, search, status, role_id} = req.query;
role_id = role_id ? role_id : null;
status = status ? status : null;
const currentPage = parseInt(page) || 1;
const perPage = recordsPerPage;
const userData = await User.find({
$and: [
{
$or : [
{username:{'$regex' : search, '$options' : 'i'}},
{email:{'$regex' : search, '$options' : 'i'}}
]
},
{
$or : [
{status : status}
]
},
{
$or : [
{role_id : role_id}
]
},
{
email: { $ne: 'xxxxx#gmail.com' }
}
]
})
.sort({_id : -1})
.populate('role_id')
.skip((currentPage - 1) * perPage).limit(perPage);

Instead of trying to rely on $or and $and in your query, you can just conditionally add fields to your query. A mongoose query is just passed an object and can be built outside the function call.
This way you won't have to worry about edge cases such as a user with status null being returned whenever you leave out the status field from your query.
let {page, search, status, role_id} = req.query;
role_id = role_id ? role_id : null;
status = status ? status : null;
const currentPage = parseInt(page) || 1;
const perPage = recordsPerPage;
const query ={
email: { $ne: 'xxxxx#gmail.com' }
}
if (status) {
query.status = status
}
if (role_id) {
query.role_id = role_id
}
if (search) {
query.username = {'$regex' : search, '$options' : 'i'}
delete query.email
query['$and'] = [
{ email: {'$regex' : search, '$options' : 'i'}},
{ email: { $ne: 'xxxxx#gmail.com' } }
]
}
const userData = await User.find(query)
.sort({_id : -1})
.populate('role_id')
.skip((currentPage - 1) * perPage).limit(perPage);
As an aside, I think a query with a $regex and a $ne on the same field (email in your example) may be very slow once executed on a large collection.

Related

Query to find document by matching a value in an object embeded in an array field

I want to query a collection "chat" whose documents have an array field "participants". This array has always two objects with the properties id and name. I want to find the document that matches the two ids of the embeded objects. For example, I want to find the following document in which the ids are "1" and "2".
//chat
//find ids 1 and 2.
//this is the document that I am looking for and should be returned.
{
_id : ytyutu876788
participants : [ {id : 1, name : Murray}, {id : 2, name : Pier} ]
}
//In this document id 1 is present but not together with id 2.
{
_id : d6t6d6tdt6
participants : [ {id : 1, name : Murray}, {id : 3, name : Gustav} ]
}
The query that I have tried to use so far is the following which returns an empty array even though I am sure that the document that I want to find exists in the collection so I know that it is the query what I am doing wrong:
try {
const userId = req.body.userId
const friendId = req.body.friendId
console.log(userId)
console.log(friendId)
await client.connect()
const query = await client.db('instagram_clone').collection('chat').find(
{"participants.id" : {userId, friendId}}
).toArray()
console.log(query)
You may use $all operator like
const query = await client.db('instagram_clone')
.collection('chat')
.find({"participants.id": {$all:[userId, friendId]}})
.toArray();
Or you may like to use $and operator like
const query = await client.db('instagram_clone')
.collection('chat')
.find({$and :[{"participants.id": userId}, {"participants.id": friendId}]})
.toArray();
This another query that does the job, in which I used the $elemmatch operator.
const firstQuery = await client.db('instagram').collection('chat').find({
participants : {
$all: [
{
$elemMatch: {
id: friendId
}
}, {
$elemMatch: {
id: userId
}
}
]
}
}).toArray();

MongoDB data matching and fetching issue while querying on an array

I want to fetch data from the MongoDB. Since I am new into Node.Js and MongoDB. I am not able to get the data.
I am passing primary category and secondary category to an API where I want to match the primary and secondary category with the array field "category" which is having two indexes 0 and 1 ,in the 0 index primary category is there and in the 1 index secondary categories are there separated by ~ .
Below is my code to get the data according to primary category but I want to get the data by matching the primary and secondary category from the db.
ProductModel
.find({ category : { $all : [req.body.primary] }})
.select('id link brand title description category image images in_stock price sale_price merchant_number part_number GroupID status promotion attributes tags currency updated -_id')
.then((productList) => {
response.status = 200;
response.msg = 'Success';
response.count = productList.length;
response.data = productList
res.json(response);
})
.catch(() => {
response.status = 500;
response.msg = 'connection error';
response.data = [];
res.json(response);
});
Sample Doc :
So I wanted to input something like ['Health','women'] & get docs where all of these elements in category array exists, kind of regex search on array elements.
Can Someone help me out to get the data from the db.
If you've to query with input as ['Health', 'women'] & get the documents which has both listed & also get the documents which has something like this : category : ["Health", "tes~men~women"] then you can try below query :
Query :
db.collection.find({
$and: [
{
category: {
$in: [
/\bwomen\b/
]
}
},
{
category: {
$in: [
"Health"
]
}
}
]
})
Js Code :
const secondary = req.body.secondary
const primary = req.body.primary
db.collection.find({
$and: [
{
category: {
$in: [
new RegExp(`\\b${secondary}\\b`, 'i')
]
}
},
{
category: {
$in: [
primary
]
}
}
]
})

How can I query whether an objectID is in an array in MongoDB with Node.js?

This is how my model looks like in Mongo:
{
"_id" : ObjectId("5951552c5bb94058b203d3e3"),
"roleName" : "Bartender",
"userList" : [
ObjectId("5926ff5088a3da5bf0d3d43b")
],
"deadline" : ISODate("2017-06-26T18:40:44.153Z"),
"__v" : 1
}
I would like to query 2 things together.
1, -Show me the model of the "role" I'm looking for.
2, -Give me true or false depending on whether the user's ID is to be found in the userList array.
exports.roleView = function(req,res, next){
const userID = req.params.userId;
const roleID = req.params.roleId;
const findUser = Role.findById({ _id: roleID
}).populate('userList', 'userName')
.then((result)=>{return result})
.catch((err)=>{return err});
const userinRole = Role.findOne({
_id:roleID, userList: userID})
.then((result)=>{return true})
.catch((err)=>{return false});
return Promise.all([findUser, userinRole])
.then((role)=>{
res.json(role);
});
};
Yet, every time don't have a match in userinRole, Mongo would just simply freeze without response.
Is it actually the proper way, or would you approach it differently? Thank you so much!

mongoose find() document with two fields with one search parameter

My node model contains following properties
firstName
lastName
age
address
I need to use mongoose find functions to filter user with firstName and lastName.
My UI pass only one search parameter. Data should filter as follows
'fistName' like 'search parameter' & lastName like 'search Parameter'.
I pass following object to find function.It did not work for me.
var criteria = {
'firstName' : req.body.customerName ? { $regex: req.body.customerName, $options: 'i' } : null ,
'lastName' : req.body.customerName ? { $regex: req.body.customerName, $options: 'i' } : null
};
If you want to get data if match with both fields of firstName and lastName then you can use $and operator with $regex.
var query = {$and:[{firstName:{$regex: req.body.customerName, $options: 'i'}},{lastName:{$regex: req.body.customerName, $options: 'i'}}]}
and If you want to get data if match with any one field of firstName and lastName then you can use $or operator with $regex.
var query = {$or:[{firstName:{$regex: req.body.customerName, $options: 'i'}},{lastName:{$regex: req.body.customerName, $options: 'i'}}]}
so can try this code:
var query = {}
if(req.body.customerName) {
query = {$or:[{firstName:{$regex: req.body.customerName, $options: 'i'}},{lastName:{$regex: req.body.customerName, $options: 'i'}}]}
}
ModelName.find(query , function (err, data) {
if(error) {
// return error
}
//return data
});
So, I think you have a logical flaw in addition to a syntactic flaw. Unless you're intentionally looking only for people who have the same first name and last name (e.g. Tom Tom), then you'll never find anyone by simply finding on both fields with the same value in each. If, as I suspect, you really want to take a search criteria and see if a user has that string in either their first name or last name, then you'll actually want to use $or.
Something like:
let query = {};
if(req.body.customerName){
const nameExp = new RegExp('^'+req.body.customerName+'$', 'i');
query = { $or : [ { firstName: nameExp }, { lastName: nameExp } ] };
}
MyModel.find(query, (err, data) => { /* do your thing */ });
var query = {}
if(req.body.customerName) {
query = {
firstName :new RegExp('^'+req.body.customerName+'$', "i"),
lastName : new RegExp('^'+req.body.customerName+'$', "i")
}
}
MyModel.find(query , function (err, data) {
// data.forEach
});
You can try pass the following criteria
var criteria = {
'firstName' : req.body.customerName ? {$regex: req.body.customerName + '.*', $options: 'i'} : null ,
'lastName' : req.body.customerName ? {$regex: req.body.customerName + '.*', $options: 'i'} : null
};

How to pass mongodb match conditions from node.js URL parameters

I have a webpage where users selects variables to filter and get database values. I tried passing the $match condition variables as below but i am not getting any results back
URL is : example.com?gender=M&date_from=20100101&date_to=201140101
I loop through the req.query to build the match condition string.
var matchQuery = [];
for (var param in req.query) {
qString = "{'" + param + "' : '" + req.query[param] + "'}";
matchQuery.push(qString);
}
var strmatchQuery = matchQuery.toString();
This outputs strmatchQuery as {'gender' : 'M'}, {'date_from' : '20100101'}, {'date_to' : '20140101'}
and then I call the mongodb aggregate function
dbmodel.aggregate( { $match: { $and: [ strmatchQuery ]} } , { $group : { _id : "$orderyear", totalorders : { $sum : 1 } } } )
But I dont get any results back. Any ideas?
function is_numeric(num) {
return !isNaN(num);
}
var matchQuery = [];
var qString = {};
for (var param in req.query) {
// You need objects in your query not strings so push objects
qString = {};
qString[param] = is_numeric(req.query[param]) ? Number(req.query[param]) : req.query[param];
matchQuery.push(qString);
}
// Removed the toString() function call
dbmodel.aggregate(
{$match: {$and: strmatchQuery}}, // Removed the array [ ]
{$group: {
_id: "$orderyear",
totalorders: {$sum: 1}}
}
);

Resources