Is there a way to only read a certain field from Mongoose? - node.js

I have a DB with a couple of levels deep nested stuff, sometimes pretty big.
now i have searched the doc and google/so, but couldn't find a simple answer:
if the schema is like:
{
roomId : String,
created : Date,
teacher : String,
students : Object,
problems : Array
}
is there a way to just read the roomId of every entry?
Not return the whole thing, but just an array of the roomIds?
(usecase: i want to make a list of all saved rooms, therefore i need absolutely nothing of all the other data, just the IDs. I want to avoid that overhead)
i'm pretty sure it can be done, but couldn't find how

Yes, use a projection
Model.findOne({...}, {roomId: 1})....

Related

Mongo db find operation query ($gte, $lt) is not working

I had a problem using query with MongoDB.
The problem was solved but I wanted to check if there was any other approach I could have taken.
At first, my model (Ad) had a property of price: {type: String}, and I tried to find by queries $gte and $lt to get ads with a price within a given range.
After reading online I figured that query operations are not working on String type properties.
Then even after changing the type to Number - price: {type: Number} - the find function didn't work properly on the price, even though on other properties which were type Number it worked as it should.
In the end, I just deleted the whole database and reupload it, and then everything worked properly (haven't changed a thing).
Has anyone had this kind of problem and solved it differently?
I'll first start by assuming you're using mongoose as the "types" you've pasted look like mongoose schema types.
You need to separate these two concepts:
The schema that represents data at the app level
The actual data in the DB.
Let's say I have this schema for a certain collection:
{ name: String }
But in the actual database there is only one document in that collection that looks like this:
{ price: 5, product_id: 1 }
Then when I query the data what do you expect to happen? do you expect mongoose to automatically generate a name for that document and delete the actual fields?
The reason it didn't "work" as you intended was that all the values were saved as string, changing the Schema does not retroactively update the database, so when you use $lt and $gte it uses string comparison which means "10" is less than "9" because that's how string comparison work.
The schema does help with newly inserted data and can cast it to the right type if supported, for that you should check the docs with what values are available.

How to make a Mongo Find Query?

I come from MySQL world so mongo queries are a bit difficult to make considering I can't really make sense of mongo style queries. I am trying to make a query for finding a string. The problem is from my very primitive knowledge about mongodb queries, the query I made isn't working. I tried it in mongoose as well in mongo shell.
Schema:
mongoose.Schema({
doctorID : String,
patientIDList : Array // array of strings
});
Query Objective:
I want to find a doctor with doctorID and then look inside the patientIDList for an ID xxx. If the patientIDList doesn't contains xxx then add xxx in the list otherwise just add nothing.
Query:
The 2 queries I tried
MyModel.findOne({'doctorID':newAppointment.doctorID}, {'patientIDList' : newAppointment.patientID}, function(err){...});
MyModel.findOne({'doctorID': newAppointment.doctorID, 'patientIDList': newAppointment.patientID}, function(err){...});
What am I doing wrong? How can I make a query?
It's always a bit of challenge to switch from a SQL to NoSQL DB and other way around. What you are trying to do is check if a value exists in an array. If the array is a string array you can simply query for the value in array.
MyModel.findOne({doctorID : newAppointment.doctorID}, {patientIDList :newAppointment.doctorID}, function(err, res){
console.log(err, res);
})
Further read: https://docs.mongodb.com/manual/tutorial/query-documents/#match-an-array-element
Relevant Question: Find document with array that contains a specific value

How to find a sub document in mongoose without using _id fields but using multiple properties

I have a sample schema like this -
Comment.add({
text:String,
url:{type:String,unique:true},
username:String,
timestamp:{type:Date,default:Date}
});
Feed.add({
url:{type:String, unique:true },
username:String,
message:{type:String,required:'{PATH} is required!'},
comments:[Comment],
timestamp:{type:Date,default:Date}
});
Now, I don't want to expose the _id fields to the outside world that's why I am not sending it to the clients anywhere.
Now, I have two important properties in my comment schema (username,url)
What I want to do is update the content of the sub document that satisfies
feed.url
comment.url
comment.username
if the comment.username is same as my client value req.user.username then update the comment.text property of that record whose url was supplied by client in req.body.url variable.
One long and time consuming approach I thought is to first find the feed with the given url and then iterating over all the subdocuments to find the document which satisfies the comment.url==req.body.url and then check if the comment.username==req.user.username if so, update the comment object.
But, I think there must be an easier way of doing this?
I already tried -
db.feeds.update({"username":"harshitladdha93#gmail.com","comments.username":"harshitladdha3#gmail.com","comments.url":"test"},{$set:{"comments.$.text":"updated text 2"}})
found from http://www.tagwith.com/question_305575_how-to-find-and-update-subdocument-within-array-based-on-parent-property
but this updates even when the comments.url or comments.usernamematches other sub documents
and I also tried
db.feeds.distinct("comments._id",{"comments.url":req.body.url})
to find the _id of document associated with the url but it returns all the _id in the subdocument
First off - you should not rely on _id not being seen by the outside world in terms of security. This is a very bad idea for a multitude of reasons (primarily REST and also the fact that it's returned by default with all your queries).
Now, to address your question, what you want is the $elemMatch operator. This says that you're looking for something where the specified sub-document within an array matches multiple queries.
E.g.
db.feeds.update({
"username":"harshitladdha93#gmail.com",
comments: {
$elemMatch: {
username: "harshitladdha3#gmail.com",
url: "test"
}
}
}, {$set: {"comments.$.text":"updated text 2"}})
If you don't use $elemMatch you're saying that you're ok with the document if any of the comments match your query - i.e. if there is a comment by user "harshitladdha3#gmail.com", and separate comment has a url "test", the document will match unless you use $elemMatch

Mongoose query with a list in the model

In my model, I have this field:
…
shows: [{
startAt: Number,
endAt: Number
}],
…
I need a query to select all objects that have a show that hasn't started yet. In other words, I want to find all models that have at least one startAt that is smaller than a given time.
Is this possible? And if so, how can I do it?
As I didn't have any test data, I couldn't test what worked. Now I do, and #joao is absolutely correct.
It seems like Mongoose doesn't care that shows is a list. It was as simple as writing
<model>.find().where('shows.startAt').gt(<constant>).exec(callback);

Node.js + Mongoose / Mongo & a shortened _id field

I'd like the unique _id field in one of my models to be relatively short: 8 letters/numbers, instead of the usual Mongo _id which is much longer. Having a short unique-index like this helps elsewhere in my code, for reasons I'll skip over here. I've successfully created a schema that does the trick (randomString is a function that generates a string of the given length):
new Schema('Activities', {
'_id': { type: String, unique: true, 'default': function(){ return randomString(8); } },
// ... other definitions
}
This works well so far, but I am concerned about duplicate IDs generated from the randomString function. There are 36^8 possible IDs, so right now it is not a problem... but as the set of possible IDs fills up, I am worried about insert commands failing due to a duplicate ID.
Obviously, I could do an extra query to check if the ID was taken before doing an insert... but that makes me cry inside.
I'm sure there's a better way to be doing this, but I'm not seeing it in the documentation.
This shortid lib https://github.com/dylang/shortid is being used by Doodle or Die, seems to be battle tested.
By creating a unique index on _id you'll get an error if you try to insert a document with a duplicate key. So wrap error handling around any inserts you do that looks for the error and then generates another ID and retries the insert in that case. You could add a method to your schema that implements this enhanced save to keep things clean and DRY.

Resources