mongoosejs get _doc without loop - node.js

I have a question after performing a find() in mongoosejs.
Is there a better way of just getting the _doc-object without looping through the whole queryresult?
I'm searching for something like model.getDoc() but I can't find it.
Thanks

Ok, I found a solution by myself. Maybe it helps anyone:
var result = model.map(function(obj){
return obj._doc;
});

To get only specific fields of documents use string with field names (separated by space) as a second parametr, if you want ommit specific fields use "-" before field name
Model.find({}, '_doc', function(){...});
But this return documents like this:
{
_id: <object id>,
_doc: <some data>
}
If you want ommit _id field:
Model.find({}, '_doc -_id', function(... {}))
Or alternative syntax:
Model.find({}).select('_doc -_id').exec()

Related

How to find all elements of array in database

I had taken this array
arr = ["1","2"]
And I want to find this id's are present in mongodb in user collection or not,
So how do I write query in mongoose for that?
user.find({'empid':'arr'},(err,res))
I am doing like this.
You should first loop through your array then run mongodb query to find item.
code should be some thing like this:
for(item in arr){
user.find({'empid':item},(err,res))
}
I think you are looking for the query operator "$in".
Here's how you can do it.
db.user.find({
"empid": {"$in": ["1", "2"] }
})
Try it on mongoplayground.net.

Mongoose-How to specify more than one attribute value in querys?

I have this mongoose query and I want to add the condition estadoPedido:"Agendado" to it? How can I do it?
Request.countDocuments(
{ estadoPedido: "Pendente", paciente: req.body.paciente }
If I understand you question right, you need to search for documents which have
- estadoPedido = 'Pendente' or 'Agendado'
- and paciente = req.body.paciente
you can use $in operator, something like this
Request.countDocuments({
estadoPedido: { $in: ['Pendente', 'Agendado'] },
paciente: req.body.paciente
})
hope it helps
you can also add multiple where clauses
Request.countDocuments()
.where("estadoPedido")
.in(['Pendente', 'Agendado'])
.where("prop2")
.in(["val1","val2"])

Mongoose partial field search without RegEx

Let's say I have this schema:
var mongoose = require("mongoose")
var userSchema = new mongoose.Schema({
name: {type: String},
// other fields
}, { collation: { locale: "en_US", strength: 1 } });
I use collation so that the search is case-insensitive
Then let's say I have a document with name "Dave"
{
name: "Dave",
// other fields
}
then, I search for it but without writing the whole word
var userList = {
.find({name: "da"})
.exec();
}
How can I make this work without using a regex expression? Which are quite slow. I have tried doing an index and then searching with the $text method but I don't know how to make it so that it searches only a specific field within the document.
I believe using REGEX is your best solution. What you are trying to do is literally what regex is designed for. Yeah it's slow, but any other option you try to implement will probably be slower.
Creating a text index, and using the $text is only designed to match full words so you cannot use this method.
If you are truly desperate, and really don't want to use regex you can try something else... Try creating and storing an object, with each possible substring in the document. Object lookup is O(1) time, which means it will be faster, but the tradeoff is you are storing an absurd amount of data in the database. If this is ok with you, then give 'er a try.
Let's use Dave for example. The object you store could look something like this:
{
"d": 1,
"da": 1,
"dav": 1,
"dave"" 1
}
We can store this object in a field called substrings. Then when we do the database lookup, it's as simple as:
User.find({ 'substrings.da': { $exists: true }})
But please consider using regex... It's so much simpler, so much cleaner and it's designed for exactly what you want.

Query MongoDB for documents with non-empty intersection of arrays

So - I have a Heroku + Node + Express + MongoDB app in development, and I've been playing around all day trying to figure out how to get the mongo query I want. In a mongo collection, every document has a property 'fruits', which is an array of strings like
fruits : ['apple', 'orange', 'lemon']
The size and contents of fruits is arbitrary. I want to query the database for all documents whose fruits array has at least one element in common with another array which I provide when I make the query. How can I achieve this?
What I've tried so far centers around the $where query and some server-side JS. If I do something like
mongo.Db.connect(mongoUri, function(err, db) {
db.collection('Users', function(er, collection) {
collection.find( {$where: 'false' } ).toArray(function(err, matches){
console.log(matches)
...
});
});
});
I get an empty array - good! And if I change the false to true, I get the whole DB - also good! Things get less good with something like the following:
collection.find( {$where: function(){return false} } ).toArray(function(err, matches){...
I get the whole DB again! I thought this would pretty obviously return the same empty array as the very first example I gave above, as per the syntax presented at http://docs.mongodb.org/manual/reference/operator/query/where/
I was trying the above out just to see if I could get anything to work with $where, but further problems arise when I try to add server-side JS to the mix. I had a look at
http://docs.mongodb.org/manual/tutorial/store-javascript-function-on-server/
and added the following to the system.js collection in my DB:
{
"_id": "isMatch",
"value": "function(){return false}"
}
and modified the above example with the line
collection.find( {$where: 'isMatch()' } ).toArray(function(err, matches){...
thinking that isMatch would now be in mongo's bag of tricks when it eval's the string (I assume it must be eval'ing the string), and the string syntax was the best bet from the playings around described above. Sadly this results in a console log of null - another flavour of wrong, I expected again an empty array.
Can anyone help me achieve the query I described above? I suspect I can work out the nitty gritty myself if you kind folks can help me understand 1. How to use the function syntax instead of the string syntax for $where, and 2. How to correctly declare a JS function in system.js for use with $where. Thanks in advance!
Your $where queries work fine when I try them in the shell, but you don't need to use $where for this query. Instead, you can use an $in that targets your fruits field to find docs that contain at least one matching fruit:
var fruits = ['apple', 'orange', 'lemon'];
db.test.find({fruits: {$in: fruits}});
Don't quite seem to know what was the case in 2013, but now I think you have to use $elemMatch along with $in that targets your fruits field to find docs that contain at least one matching fruit:
var fruits = ['apple', 'orange', 'lemon'];
db.test.find({fruits: {$elemMatch: {$in: fruits}}});

sorting alpha with mongoose

I'm trying to sort via mongoose 3.6.20 and I am receiving some unexpected results.
I have a list of companies with a name. At first I thought that maybe it was sorting in a case sensitive way. Which based on articles, I expect was true.
I'm now using a virtual property to down case the sort field. However, I'm still getting unexpected results.
CompanySchema.virtual('name_lower').get(function(){
return this.name.toLowerCase();
});
and when I sort
Company.find().sort({ name_lower: 1 });
I'm getting it in the following order:
company name
google
company name (yes a duplicate for testing)
I'm also outputting the value of my virtual property and it looks right. There is no whitespace or funky characters that would result in the 2nd 'company name' from appearing after google.
Using nodejs, express, mongoose.
What am I missing or doing incorrectly?
Update:
Based on the information provided in the answers, I refactored my schema to include some normalized fields and hooked into the pre save event of my document, where I update those normalized fields and sort using them in all future queries.
CompanySchema.pre('save', function(next){
this.normalized_name = this.name;
});
Next, is in the schema I use:
var CompanySchema = mongoose.Schema({
...
normalized_name: { type: String, set: normalize },
...
});
Where normalize is a function that for now, returns a lowercase version of the value passed into it. However, this allows me to expand on it later really fast, and I can quickly do the same to other fields that I might need to sort against.
As of MongoDB v3.4, case insensitive sorting can be done using collation method:
Company.find()
.collation({locale: "en" }) //or whatever collation you want
.sort({name:'asc'})
.exec(function(err, results) {
// use your case insensitive sorted results
});
Unfortunately MongoDB and Mongoose does not currently support complex sorting, so there are 2 options:
As you said, create a new field with the names sanitized to be all lowercase
Run a big for loop over all the data and update each company name to it's lower case form:
db.CompanyCollection.find().forEach(
function(e) {
e.CompanyName = e.CompanyName.toLowerCase();
db.CompanyCollection.save(e);
}
)
or
db.CompanyCollection.update({_id: e._id}, {$set: {CompanyName: e.CompanyName.toLowerCase()
Please see Update MongoDB collection using $toLower and Mongoose: Sort alphabetically as well for more info.
I want to put out that in this hook:
CompanySchema.pre('save', function(next){
this.normalized_name = this.name;
});
You'll have to call next(); at the end, if you want the normalized_name to be saved in the database, so the pre save hook would look like:
CompanySchema.pre('save', function(next){
this.normalized_name = this.name;
next();
});
This answer seems to be more helpful to me. I had to consider diacritics along with the case so I had used strength:3.
Mongoose: Sort alphabetically

Resources