mongoose find() document with two fields with one search parameter - node.js

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
};

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();

Query nested object mongoose

i am trying to reproduce the "like" behavior in mongoose by searching all elements where user name is something like "abcd..."
this function return abject that i feed db.find function with
const rgx = (pattern) => new RegExp(`.*${pattern}.*`);
const orFilter = [];
fields.forEach((field) => {
if (field.includes('.')) {
const [parent, child] = field.split('.');
orFilter.push({
[parent]: { [child]: { $regex: rgx(searchText), $options: 'i' } },
});
} else {
orFilter.push({ [field]: { $regex: rgx(searchText), $options: 'i' } });
}
});
return { $or: orFilter };
entry 1: ['city','zipCode'] working ok
entry 2 : ['city','zipCode','user.name'] does not work.
i have this message *CastError: Cast to ObjectId failed for value
{ name: { '$regex': /.abc./, '$options': 'i' } }
*
the solution to my probleme was found by using aggregation visit
https://www.mongodb.com/docs/manual/reference/method/db.collection.aggregate/!
i tried to access a value stored in another table user.name

Build Mongo Query based on query parameters in url

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.

How to make case insensitive query in mongodb

this API is getting called for per change. it can be a number or name field. here the task is I want to search name with case-insensitively.
router.get('/v1/branch/search/customers/:phoneNumber',authenticate , (req, res) => {
var regex = "/^"+req.params.phoneNumber+"/", name ="/^"+req.params.phoneNumber+"$/i";
Customer.find({
subscriberId: req.user.subscriberId,$or:[{$where:regex+'.test(this.phoneNumber)'},{$where:name+'.test(this.name)'},{$where:regex+'.test(this.name)'}],
_creator : req.user._id
},{name:1,phoneNumber:1,_id:0}).sort({name: 1}).then((customer) => {
res.send({'statusCode':0,'data':customer});
}, (e) => {
console.log(e);
res.status(200).send({'statusCode':2,'message':e.message});
});
});
Above code is working case-insensitively only for some names not for all data. I am not getting what wrong I am doing here.
you can use regex queries
{ "name" : { $regex: /Ghost/, $options: 'i' }
including this to your code will solve the problem of case-insensitively.

MongooseJS - How to find the element with the maximum value?

I am using MongoDB , MongooseJS and Nodejs.
I have a Collection ( called Member ) with the following Fields -
Country_id , Member_id , Name, Score
I want to write a query which returns the Member with the max Score where Country id = 10
I couldnt find suitable documentation for this in MongooseJS.
I found this at StackOVerflow ( this is MongoDB code )
Model.findOne({ field1 : 1 }).sort(last_mod, 1).run( function(err, doc) {
var max = doc.last_mod;
});
But how do I translate the same to MongooseJS ?
Member
.findOne({ country_id: 10 })
.sort('-score') // give me the max
.exec(function (err, member) {
// your callback code
});
Check the mongoose docs for querying, they are pretty good.
If you dont't want to write the same code again you could also add a static method to your Member model like this:
memberSchema.statics.findMax = function (callback) {
this.findOne({ country_id: 10 }) // 'this' now refers to the Member class
.sort('-score')
.exec(callback);
}
And call it later via Member.findMax(callback)
You do not need Mongoose documentation to do this.
Plain MongoDb will do the job.
Assume you have your Member collection:
{ "_id" : ObjectId("527619d6e964aa5d2bdca6e2"), "country_id" : 10, "name" : "tes2t", "score" : 15 }
{ "_id" : ObjectId("527619cfe964aa5d2bdca6e1"), "country_id" : 10, "name" : "test", "score" : 5 }
{ "_id" : ObjectId("527619e1e964aa5d2bdca6e3"), "country_id" : 10, "name" : "tes5t", "score" : -6 }
{ "_id" : ObjectId("527619e1e964aa5d2bdcd6f3"), "country_id" : 8, "name" : "tes5t", "score" : 24 }
The following query will return you a cursor to the document, you are looking for:
db.Member.find({country_id : 10}).sort({score : -1}).limit(1)
It might be faster to use find() than findOne().
With find().limit(1) an array of the one document is returned. To get the document object, you have to do get the first array element, maxResult[0].
Making Salvador's answer more complete ...
var findQuery = db.Member.find({country_id : 10}).sort({score : -1}).limit(1);
findQuery.exec(function(err, maxResult){
if (err) {return err;}
// do stuff with maxResult[0]
});
This is quick and easy using the Mongoose Query Helpers.
The general form for this could be:
<Your_Model>.find()
.sort("-field_to_sort_by")
.limit(1)
.exec( (error,data) => someFunc(error,data) {...} );
tldr:
This will give you an array of a single item with the highest value in 'field_to_sort_by'. Don't forget to access it as data[0], like I did for an hour.
Long-winded: Step-by-step on what that string of functions is doing...
Your_Model.find() starts the query, no args needed.
.sort("-field_to_sort_by") sorts the everything in descending order. That minus-sign in front of the field name specifies to sort in descending order, you can discard it to sort in ascending order and thus get the document with the minimum value.
.limit(1) tells the database to only return the first document, because we only want the top-ranked document.
.exec( (error,data) => someFunc(error,data) {...} ) finally passes any error and an array containing your document to into your function. You'll find your document in data[0]
You can also use the $max operator:
// find the max age of all users
Users.aggregate(
{ $group: { _id: null, maxAge: { $max: '$age' }}}
, { $project: { _id: 0, maxAge: 1 }}
, function (err, res) {
if (err) return handleError(err);
console.log(res); // [ { maxAge: 98 } ]
});

Resources