How to make case insensitive query in mongodb - node.js

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.

Related

Updating nested array mongodb

I think there are multiple ways to do this, and that has me a little confused as to why I can't get it to work.
I have a schema and I would like to update Notes within it but I can't seem to do it. Additionally, if I want to return the notes how would I go about doing it?
schema :
{
_id : 1234
email : me#me.com
pass : password
stock : [
{
Ticker : TSLA
Market : Nasdaq
Notes : [
"Buy at 700",
"Sell at 1000"
]
},
{
Ticker : AAPL
Market : Nasdaq
Notes : [
"Buy at 110",
"Sell at 140"
]
},
]
}
Each user has a list of stocks, and each stock has a list of notes.
Here is what I have tried in order to add a note to the list.
router.post(`/notes/add/:email/:pass/:stock/:note`, (req, res) => {
var email = req.params.email
var pass = req.params.pass
var note = req.params.note
var tempStock = req.params.stock
userModel.findOne({email: email} , (err, documents)=>{
if (err){
res.send(err);
}
else if (documents === null){
res.send('user not found');
}else if (bcrypt.compareSync(pass , documents.pass)){
userModel.findOneAndUpdate({email : email , "stock.Ticker" : tempStock}, {$push : {Notes : note}} ,(documents , err)=>{
if(err){
res.send(err);
}else {
res.send(documents.stock);
}
})
}
})
})
Thanks :)
Currently, you are pushing the new note into a newly created Notes property inside the model instead of into the Notes of the concrete stock. I am not completely aware of the mongoose semantics but you need something like this:
userModel.findOneAndUpdate({ email: email, "stock.Ticker": tempStock }, { $push: { "stock.$.Notes": note } }, (documents, err) => {
$ gives you a reference to the currently matched element from the stock array.
For the second part, I am not sure what you mean by
Additionally, if I want to return the notes how would I go about doing it?
They should be returned by default if you're not doing any projection excluding them.
Also, as per the docs(and general practise), the callback for the findOneAndUpdate has a signature of
(error, doc) => { }
instead of
(documents, err) => { }
so you should handle that.

Pull objects from array in embedded MongoDB document

I've been unable to figure out a way to to remove objects from arrays in embedded mongoDB documents.
My schema holds a user and a list of flower objects. It looks like this:
const UserSchema = new Schema({
name : {
type : String,
required : true
},
flowers : [
{
name : {
type : String,
required : true
},
water_freq : {
type : Number,
required : true
}
}
]
});
I've managed to add flower objects like so:
router.post('/:id/flowers/add', (req, res) => {
const { name, water_freq } = req.body;
User.findByIdAndUpdate(
req.params.id,
{
$push : {
flowers : { name, water_freq }
}
},
{ new: true }
).then((user) => res.json(user));
});
I want to delete flowers from users by their id but I'm unable to get it to work.
The code below is my non-working attempt at it.
router.delete('/:id/flowers/delete/:flowerid', (req, res) => {
User.findByIdAndUpdate(req.params.id, {
$pull : {
flowers : { _id: req.params.flowerid }
}
}).then((user) => res.json(user));
});
I would greatly appreciate if someone can help me get this right.
One possible cause is, in your query {$pul: xxxx}, MongoDB is expecting a BSON type object id that was auto generated for each flower entry, while you are giving a string. So you may want to convert it to the proper type before doing the query:
try:
router.delete('/:id/flowers/delete/:flowerid', (req, res) => {
User.findByIdAndUpdate(req.params.id, {
$pull : {
flowers : { _id: ObjectId(req.params.flowerid) }
}
}).then((user) => res.json(user)); });
To see more about the objectId
Thanks for the replies!
I did some more testing with postman and found out that in fact the code I posted in my question did work after all. What set me off was that the response with the user document still displayed the flower I had just deleted, which made me think it didn't work.
I still have no idea why that is, or if there's a way to get a response with the updated user. But the deletion seems to work as intended.

Find specific data in MongoDB via NodeJS

I need to find specific data in my MongoDB for the rest API but it's returning null.
app.get('/api/v1/champions/:name', (req, res) => {
db.find({"champions": req.params.name}, (err, champion) => {
res.json(err)
})
})
Here is my MongoDB Schema:
champions: {
champ_name_1: {
dmg: Number,
cost: Number
},
champ_name_2: {
....
}
}
Since you are checking to see if a key exists in the champions object you'll need to write the query differently.
If your data was formatted like this then your query would work. (champions is a String)
{
"champions": "champ_name_1",
"dmg": 123,
"cost": 123
}
To check if a key exists in an object in mongo, use a query like this.
const champKey = 'champions.' + req.params.name;
db.find({ [champKey]: { $exists: true } });
https://docs.mongodb.com/manual/reference/operator/query/exists/
you can use mongoose package
here
and simply use the mongoose's find() methond to find particular data as providing to it.
For Example: find({_id: MY_ID_HERE});

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

Mongoose searching FindOne with multiple arguments

My first attempt at building something with Angular + express + mongodb, so I'm probably going about this completely the wrong way. Express is being used to serve up json. Angular then takes care of all the views etc.
I'm using Mongoose to interact with Mongo.
I have the following database schema:
var categorySchema = new mongoose.Schema({
title: String, // this is the Category title
retailers : [
{
title: String, // this is the retailer title
data: { // this is the retailers Data
strapLine: String,
img: String , // this is the retailer's image
intro: String,
website: String,
address: String,
tel: String,
email: String
}
}
]
});
var Category = mongoose.model('Category', categorySchema);
and in Express I have a couple of routes to get the data:
app.get('/data/categories', function(req, res) {
// Find all Categories.
Category.find(function(err, data) {
if (err) return console.error(err);
res.json(data)
});
});
// return a list of retailers belonging to the category
app.get('/data/retailer_list/:category', function(req, res) {
//pass in the category param (the unique ID), and use that to do our retailer lookup
Category.findOne({ _id: req.params.category }, function(err, data) {
if (err) return console.error(err);
res.json(data)
});
});
The above works - I'm just having big problems trying to get at a single retailer. I'm passing the category, and retailer id through... I've tried all sorts of things - from doing a find on the category, then a findOne on the contents within... but I just cant get it to work. I'm probably going about this all wrong...
I found this thread here: findOne Subdocument in Mongoose and implemented the solution - however, it returns all my retailers - and not just the one I want.
// Returns a single retailer
app.get('/data/retailer_detail/:category/:id', function(req, res) {
//pass in the category param (the unique ID), and use that to do our retailer lookup
Category.findOne({_id: req.params.category , 'retailers.$': 1}, function(err, data) {
console.log(data);
if (err) return console.error(err);
res.json(data)
});
});
Thanks,
Rob
Now that I see your full filter/query, you should be able to use the array positional operator in this case as part of the projection rather than doing client side filtering:
app.get('/data/retailer_detail/:category/:id', function(req, res) {
//pass in the category param (the unique ID), and use that to do our retailer lookup
Category.findOne({
/* query */
_id: req.params.category ,
'retailers._id' : req.params.id
},
{ /* projection */
"retailers.$" : 1
},
function(err, data) {
var retailer = _.where(data.retailers , { id : req.params.id });
if (err) return console.error(err);
res.json(retailer)
});
});
For the { "retailers.$" : 1 } to work properly, the query must include a field from an element in the array. The $ operator returns the first match only.
The guys next door use Mongo + Express and gave me some pointers: they explained to me how mongo worked, and advised I should use underscore.js to assist with my filter.
They said I needed to pull the entire category out - and then run the filter. I don't strictly need , 'retailers._id' : req.params.id} but they said to leave it in as it guaranteed that the category would only be returned if an item within it contained that information. I still don't really know why or how... So can't really mark this as solved.. it it solved, but I don't really get why as yet - so will do more reading :)
app.get('/data/retailer_detail/:category/:id', function(req, res) {
//pass in the category param (the unique ID), and use that to do our retailer lookup
Category.findOne({_id: req.params.category , 'retailers._id' : req.params.id}, function(err, data) {
var retailer = _.where(data.retailers , { id : req.params.id });
if (err) return console.error(err);
res.json(retailer)
});
});

Resources