How to query an attribute from an object inside of an array with Mongoose - node.js

I am trying to filter a list of 'professionals' using model.find() from Mongoose. The query I have works normally in MongoDB Compass but with Mongoose it does nothing.
The model goes like this:
{
name: string,
email: string,
password: string,
phoneNumber: number,
city: string,
myDescription: string,
specialty: [
{ name: string, certificate: string, isCertified: boolean }
],
image: { profile: string, jobs: [strings] },
availability: Boolean
}
The query in MongoDB Compass is { specialties: { $elemMatch: { name: 'Soldador General', isCertified: true } } } and it returns the list of 'professionals' as expected. When I use it in Mongoose it returns the entire list, so no filter.
Going through the documentation of Mongoose there is a method Query.elemMatch() but the problem is that the filter is dynamic, I want the users to filter by city, specialty or both, and also I might add some filters in the future. For now the queries look something like:
{ specialties: { $elemMatch: { name: 'Soldador General', isCertified: true } } }
{ city: 'Barranquilla' }
{ city: 'Barranquilla', 'specialties': { $elemMatch: { name: 'Soldador General', isCertified: true } } }
And so I don't see how to do this dynamically with Query.elemMatch(). BTW I retrieve the object using React useSearchParams and send the request via NodeJS.
Any help or guidance is highly appreciated!

Related

remove a particular array element from mongodb on clicking the element

I'm using this code for removing a particular array element stored in MongoDB when clicked that from the app. But this code is not working.
schema structure looks like this -
const tagsSchema = new Schema({
category: {
type: String,
required: true
},
tname: { type: Array }
}, { _id: true });
Below is the code I'm using for removing array element from db -
Tags.updateOne({ tname: req.params.name }, { $pull: { _id: [req.params.id] } })
For example - "tname": "technical", "nontechnical"
Now, technical is being clicked in the app to remove, but with the code I'm using it's not getting removed.
you can use directly your element_value without [] after your array field, like below..
Tags.updateOne({tname: req.params.name}, { $pull: { your_array_field: req.params.id } } )
You have to find the specific tag by its "_id" and then remove the particular name from the "tname" array.
Tags.updateOne({ _id: req.params.id }, { $pull: { tname: req.params.name } })

MongoDB - update data in array of objects within object

I have a document in mongoDB structured like that
_id: ObjectId("generatedByMongo"),
name: {
required: true,
type: String,
trim: true
},
last: {
required: true,
type: String,
trim: true
},
grades: [{
grade: {
_id: ObjectId(""),
grade: Number,
date: date
}
}]
And to server I send array of objects containing 3 fields
[
{studentId}, {gradeId}, {newGrade}
]
What I'm trying to accomplish is I want to find in within that user collection grade with given gradeId and update it's value to newGrade. As far as I tried to do that I have done this
router.patch('/students/updateGrade',async(req,res) => {
const studentId = req.body.updateGradeArray[0].studentId;
const gradeId = req.body.updateGradeArray[0].gradeId;
const newGrade = req.body.updateGradeArray[0].newGrade;
try {
const student = await Student.find({_id: studentId})
.select({'grades': {$elemMatch: {_id: gradeId}}});
} catch(e) {
console.log(e);
}
}
);
If you intend to update just grade.grade(the number value), try this:
Student.updateOne(
// Find a document with _id matching the studentId
{ "_id": studentId },
// Update the student grade
{ $set: { "grades.$[selectedGrade].grade": newGrade } },
{ arrayFilters: [{ "selectedGrade._id": gradeId }] },
)
Why this should work:
Since you are trying to update a student document, you should be using one of MongoDB update methods not find. In the query above, I'm using the updateOne method. Inside the updateOne, I am using a combination of $set and $[identifier] update operators to update the student grade.
I hope this helps✌🏾

Best way to partial update nested object data in mongodb in node js

I have searched many questions on nested objects, but all I found where related to array[s].
I am looking for a updating simple nested object in mongoose.
Once created a document, I want to partially update basicDetails and agentDetail object.
Example schema :
var applicationSchema = new Schema({
title: String,
author: String,
basicDetails:{
appId:Number,
fname:String,
mname:String,
lname:String
},
agentDetails:{
agentName:String,
bankName:String,
bankCode:Number,
agentCode:Number
}
comments: [{ body: String, date: Date }],
createdDate: { type: Date, default: Date.now }
})
I Want to update only fname and last name from basicDetails,title, bankName and agentCode from agentDetails.
Request is :
{
title:Update,
basicDetails:{
fname:Neeraj,
lname:singh
},
agentDetails:{
bankName:String,
agentCode:Number
}
}
There is no document for the same that I could find.
Just use the dot notation
db.collection.findOneAndUpdate(
{ // match your document }
{ $set: { "basicDetails.fname": newName, "agentDetails.title": newTitle } }
)

What is the best way to handle querystrings in an express api?

I am a beginner nodejs developer, working on developing an express rest api with optional query params.
For example consider the following schema for a user:
phone: {
countryCode: String,
number: phoneType
},
phoneVerified: { type: Boolean, default: false },
emailVerified: { type: Boolean, default: false },
rating: Number,
balance: { type: Number, default: 0 },
occupation: String,
gender: { type: String, enum: genders },
I want to expose this resource at /users and allow querying through optional query strings.
For ex, /users?emailVerified=true&phoneverified=false&gender=male&occupation=plumber&limit=10
This should return all the users which satisfy the criteria, while keeping almost all of the options optional.
What is the best way to do this in a maintenable and futureproof way?
Appraoch 1: My first approach was to use if blocks to check which parameters exist in the query and build mongoose queries accordingly, but that looks ugly and very hard to read.
queryObj = {};
if (req.query.occupation) {
queryObject = {
...queryObject,
occupation: req.query.occuption
};
}
if (req.query.phoneVerified) {
queryObject = {
...queryObject,
phoneVerified: req.query.phoneVerifed
};
}
const users = await User.find(queryObject);
I also found the querymen package which looks promising. If someone experinced could guide me as to what is the best practice? Thanks in advance
you are doing it in right way. you can also try
queryObject = {};
if (req.query.params.occupation) {
queryObject.occupation= req.params.occuption
}
if (req.params.phoneVerified) {
queryObject.phoneVerified= req.params.phoneVerifed
}
const users = await User.find(queryObject);
you can add new properties to json using "."

Don't know how to write complex Mongoose query

Here is the schema used to display current tournaments in one country:
var TournamentSchema = new mongoose.Schema({
name: String,
location: String,
googlelink: String,
description: String,
format: String,
date: Date
closedate:Date
type:String
});
The webpage also has filters like in ecommerce sites. If suppose I get one query from url like:
https://www.example.com/format=5v5%7v7&&location=hyd&&ahmedabad
I need to make query for tournaments which are 5v5 or 7v7 format and which are in Hyd and Ahmedabad.
I need to write generalised query as I don't know about number of places and format.
I don't know how to do this. Can someone help me out?
Here is an example of a query I wrote that uses mongoose $or.
Event.find( { $or: [{ joiners: req.user._id }, { creator: req.user._id}] } )
.populate('creator')
.exec(function(err, goevent){
if(err){
console.log(err)
} else {
res.json(goevent)
}
})
Basically in your query param {} you can pass in something like this:
{ $or: [ { query: one}, {query: two} ] }
Like so:
Model.find({ $or: [ { query: one}, {query: two} ] }, function(err, data){
//err & success handlers
}
Once you figure that out, you can use a bunch of other logical operators as well, like $and.
if the object you are querying is nested you just do 'some.property' (use string syntax when accessing objects with dot notation)

Resources