mongoose search using regex on findbyid - node.js

I need to find a user by his mongodb collection's _id ,
in need the search to be done using the first 5 characters in the user id
example with 5e9cca i can find the collection id 5e9cca24beabb96a4caedc35
var id = req.body.id
User.findById({ _id : { $regex: '^id', $options: 'i' } },
(err, user) => {
if (err) {
console.log(err);
res.status(400)
}
with this code i got this error :
MongooseError [CastError]: Cast to ObjectId failed for value "{ _id: { '$regex': '^id', '$options': 'i' } }" at path "_id" for model "User"
PS : The search using the hole id is working

Mongoose's .findById() will take in a string & internally it will convert string into ObjectId(). So .findById() is kind of a wrapper to MongoDB's native function .findOne() and all it can take is a string. Additionally you can not do regex search on _id field as it's not of type string. If at all you need to do this, try below :
On MongoDB version >4.0 :
db.collection.aggregate([
/** Create a field of type 'string' from `_id`*/
{ $addFields: { convertedId: { $toString: "$_id" } } },
/** Regex search against it */
{
$match: {
convertedId: {
$regex: "^1a934e",
$options: "i"
}
}
},
/** Remove additionally added field */
{ $project: { convertedId: 0 } }
])
Test : mongoplayground

Related

Mongoose FindOne returns all children

Is it ok that findOne returns all subdocument in array? I mean isn't it take a long time to execute that, or is there way to get document with only one subDoc ?
my code :
userModel
.find({
{_id: userId,},
{ contacts: { $elemMatch: { userId: contactId } } }
).select('name contacts');
I cant use userModel.contacts.id() cause I don't have id
How can I add a conversation id to this found document
How can I do
const userData = userModel.findById(userId)
.where('contacts')
.elemMatch({ userId: contactId })
and get the result with only one contact (in order not to search for a contact from the entire array)
and simply change relation like
userData.contacts[0].conversation = conversationId;
await userData.save()
How about this:
db.collection.update({
_id: 1
},
{
$set: {
"contacts.$[x].conversation": 3
}
},
{
arrayFilters: [
{
"x.userId": "John"
}
]
})
playground

$or doesn't work for subdocument level search

Search retrieves result only in parent level. search with $or condition returns empty array for subdocument level filter/search. $or doesn't work for subdocument level search. Any fixes for this or any mistakes in my code?
exports.getAllProduct = (req, res, next) => {
categories.find({$or:[{“categoryName”:{ $regex: req.params.id, $options: ‘i’ }},
{“subcategory.$.productName”:{ $regex: req.params.id, $options: ‘i’ }}]},
(err, products) => {
console.log(“Products:“+JSON.stringify(products));
if (err) {
return res.status(400).json({
error: “No Products found”+err
});
}
res.status(200).json(products)
});
};
const categorySchema = new mongoose.Schema({
categoryName: {
type: String,
trim: true
},
subcategory: [ {
subcategoryName: {
type: String,
trim:true
},
productCode: {
type: String,
trim: true
}]});
http://localhost:3000/category/getAllProduct/fruits
What mistake why $or is not working? I'm using mongoDB 4.4.1 and mongoose 5.10.8 and Mac OS Catalina.
As I can see sub-category is an array..you should check in the second parameter of the $or if the input is “$in” array.
Check this post
MongoDB query IN array of object
If I'm reading your mongo query correctly, you have a $ in subcategory.$.subcategoryName which is most likely causing the issue you are seeing. Use subcategory.subcategoryName to query against that value.
See below:
categories.find({
$or:[
{
“categoryName”:{
$regex: req.params.id,
$options: 'i'
}
},
{
“subcategory.subcategoryName”: {
$regex: req.params.id,
$options: 'i'
}
}
]},
(err, products) => {}
);
Also, always try to format your code cleanly as in this example. It makes finding solutions easier.
If you do not need the query to be case insensitive the below query will be cleaner:
categories.find({
$or:[
{
“categoryName”: req.params.id
},
{
“subcategory.subcategoryName”: req.params.id
}
]},
(err, products) => {}
);

NodeJS Mongoose wont accept string variable in $regex

I got one record with admin.name = "FooBar"
And I want to do a findOne on the name but case insensitive.
In Studio3T this works fine...
db.admin.findOne(
{ name: { $regex: /^FoObAr/i } }
)
But in nodeJS I cant seem to get a variable containing the regexp into the find statement...
Let ID = "FoObAr"
return resolve( adminModel.findOne( { "name" : { $regex: "/^" + ID + "$/i"} } ) );
This one results in... (which gives 0 results)
Mongoose: admin.findOne({ name: { '$regex': '/^FoObAr$/i' } }, { projection: {} })
I also tried
Let ID = "FoObAr"
return resolve( adminModel.findOne( { "name" : { $regex: /^ ID $/i } ) );
This one results in... (which gives 0 results)
Mongoose: admin.findOne({ name: { { $regex: /^ ID $/i } }, { projection: {} })
Any ideas?
Please use RegExp function
admin.find({name:new RegExp(['^',ID, '$'].join(''), 'i')}).projection({})
You should pass RegExp object, not string.
adminModel.findOne({ "name" : { $regex: new RegExp(/^FoObAr/, 'i') } })
With variable ID it will look like
adminModel.findOne({ "name" : { $regex: new RegExp(`^${ID}$`, 'i') } })

Delete a single record from an array of nested document in mongodb

I want to delete just one contact from the contacts array of a particular user
from mongdb dynamically using nodejs
{
_id:ObjectId("532737785878v7676747788"),
firstname:"Mark",
lastname:"Anthony",
email:"xyz#gmail.com",
contacts:[
{
_id:ObjectId("678758478fr7889889)",
firstName:"James",
lastName:"Cole",
phoneNo:"09746"
},
{
_id:ObjectId("678758478fr7889889)"
firstName:"Jane"
lastName:"Doe"
phoneNo:"12345"
}
]
}
I tried this:
User.updateOne(
{email:'xyz#gmail.com', 'contacts._id':678758478fr7889889},
{ $pull : { contacts : { firstName:'Jane', lastName:'Doe', phoneNo:'12345'} } },
{multi:true},
);
I am not getting any error messages and it's not deleting any contact
db.collection.update({
email:'xyz#gmail.com',
contacts: {
$elemMatch: {
"_id": "678758478fr7889889"
}
}
}, {
$pull: {
contacts: {
_id: '678758478fr7889889'
}
}
}
)
Mongoose would use defined schema to create ObjectId's in DB while on writes but it would not use schema on _id(ObjectId's) for find queries, So you've to explicitly say that _id is an ObjectId(). Please have this in your code :
const mongoose = require('mongoose'); // Ignore this if you've already imported.
const ObjectId = mongoose.Types.ObjectId;
// Assuming id is the value you've got in request.
User.updateOne(
{email:'xyz#gmail.com', 'contacts._id':new ObjectId(id)},
{ $pull : { contacts : { firstName:'Jane', lastName:'Doe', phoneNo:'12345'} } });
// you can do the same with `findOneAndUpdate` with options {new: true} which would return updated document, by default it would be false that meant to return old document.
User.findOneAndUpdate(
{email:'xyz#gmail.com', 'contacts._id':new ObjectId(id)},
{ $pull : { contacts : { firstName:'Jane', lastName:'Doe', phoneNo:'12345'} } }, {new : true});

Doing partial search with mongoose

I'm trying to get Mongoose to return results in a query when I only give a partial query. For example: I have a 'Company' schema that lists a bunch of companies. A document example:
{
"_id" : ObjectId("57aabeb80057405968de1539"),
"companyName" : "Vandelay Industries",
"owner" : "Ary Vandelay",
"inception" : 2012,
"__v" : 1
}
So if I do a search query like this:
Company.findOne(
{ companyName: Vandelay Industries }, function (err, company) {
if (company) {
//do stuff
}
});
This will produce the document. But If I do the following, I won't get a result:
Company.findOne(
{ companyName: Vandelay }, function (err, company) {
if (company) {
//do stuff
}
});
I would like to be able to do these sorts of partial searches and still get a result. Is there any way to do that with Mongoose?
In order to achieve this you can use a regex search to get the required result.
var searchKey = new RegExp('Vandelay', 'i')
Company.findOne({ companyName: searchKey }, function (err, company) {
if (company) {
//do stuff
}
});
Refer this stackoverflow post.
You can use this query to get result on specific value
Company.findOne({"companyName": /Vandelay/},function(err,company){
if(!err){
console.log(company);
}
});
To get result faster you should use indexing ref https://docs.mongodb.com/manual/text-search/.
db.Company.createIndex( { companyName: "text" } )
then you can search
db.Company.find( { $text: { $search: "company name" } } )
But this only support full word search not partial, so adding an extra line to this will help
db.Company.find({ $or: [
{ $text: { $search: query } },
{ companyName: { $regex: '^' + 'copmany name'} }
]}
This will help you search the results faster than normal
Are you doing a fulltext search? If you do that:
TagGroup.find({
$text: {
$search: text
}
}, {
score: {
$meta: "textScore"
}
}).sort({
score: {
$meta: 'textScore'
}
})
Try that code below. Also you need create a index on that schema
TagGroupSchema.index({
"$**": "text"
});
Here is the document
You can use elasticsearch to do that either, when the documents grows, you should consider this way.

Resources