How to get array of json objects rather than mongoose documents - node.js

When I do the .find operation like the following:
Collection.find({name: 'Erik'}, function (err, docs) {
// do momething
});
'docs' variable is populated with an array of fully functional mongoose documents. But I need to get an array of pure JSON objects.
I know I can loop through the 'docs' array by forEach and get an objects by using .toJSON() method. Does mongoose support the feature, I'm interested?

If you're using Mongoose 3.x you can use the lean query option to do this:
Collection.find({name: 'Erik'}).lean().exec(function (err, docs) {
// docs are plain javascript objects instead of model instances
});

.exec(function(err, docs){
docs= docs.map(o => o.toObject());
This will include virtuals and getters

Map through results and convert each to JS object:
const result = await model.find({some: 'query'});
return result.map((r) => r.toObject());

Related

How can i convert the mongoose aggregation array of object of object response into json object response

I have you mongoose aggregation in nodejs to get the multiple distinct values of the documents. The response I got is an array of the object of objects. How can convert that into a general JSON object response?
You can use lean() function exposed by mongoose
And example would be:
YourModel.find().lean().exec(function (err, users) {
return res.end(users);
}
OR
const leanDoc = await MyModel.findOne().lean();
Enabling the lean option tells Mongoose to skip instantiating a full Mongoose document and just give you the POJO.
Doc Link: https://mongoosejs.com/docs/tutorials/lean.html#using-lean

How to get all keys + in a collection + mongodb +mongoose

I want to get all distinct keys from a collections in mongoDB.
I refereed the following links:
Get names of all keys in the collection
Querying for a list of all distinct fields in MongoDB collection and etc.
But still i didn't get the right solution...
As i am using mongoose in the first link reference syas runCommand is not a function.
As findOne() will give the first document keys alone but i need all distnct keys
userModel.findOne(condition, projection, callback)
Please share your ideas..
If you are using Mongoose 3.x, then you can try this :
userModel.find().distinct('_id', function(error, ids) {
// ids is an array of all ObjectIds
});
Or you can find all the documents and extract key from that like :
var keys = {};
var docKeys = [];
userModel.find({}, function(err, allDocs){
allDocs.forEach(function(doc){
docKeys = Object.keys(doc);
docKeys.forEach(function(docKey){
if(!keys[docKey]) keys[docKey] = true;
})
})
})
I have just written for getting logic, you can change according to your requirements and efficiency
Try like this you will get all of your keys defined into your mongoose model/Schema.
import Model from 'your_model_path'
for(let property in Model.schema.obj){
console.log("key=====>",property);
}

Mongodb multiple conditions

New to MongoDB and express interactions. I'm trying to query the database based on URL parameters, essentially I want to grab URL parameters then add them to an object if they exist to use when querying the database. I set up my express path and understand that the find() method accepts an object, when I hard code the key-value pair like below I get the correct data but when I set an object called filter with the same key-value pairs as the hard-coded example and uncomment filter and comment state and type then pass it to the find method I get an empty array. Whats the reason for this and what's the best way to achieve this?
app.get('/query', function (req, res) {
var filter = {
state: "florida",
type: "red"
}
db.collection('tickets').find({
//filter
state:"florida",
type:"red"
})
.toArray(function (err, documents) {
// Here is where we decide what to do with the query results
if (err)
throw err
res.send(documents)
})
});
The find method accepts a query object as the first parameter, the query object is your filter object yourself. therefore, you should do it like this:
db.collection('tickets').find(filter)
.toArray(function (err, documents) {
// Here is where we decide what to do with the query results
if (err)
throw err
res.send(documents)
})

mongoose - how come findOne returns the mongoose Model object but find doesn't?

How come when I use mongoose findOne method, the object it found that is returned in the callback is a valid mongoose Model object (meaning I can call the mongoose model helper methods on it, like id for sub-documents or remove to delete it), and when I call mongoose find methode I just get back a javascript object representing the document i was looking for ?
findOne gives you a single mongoose document whereas find gives you an array of all matching mongoose documents back, not a cursor.
YourModel.find({ something: true }, function (err, docs) {
if (err) return handleErrorSomehow(err)
console.log(Array.isArray(docs)) // true
docs.forEach(function (doc) {
console.log(typeof doc.save) // function
})
})

How to get all count of mongoose model?

How can I know the count of a model that data has been saved? there is a method of Model.count(), but it doesn't seem to work.
var db = mongoose.connect('mongodb://localhost/myApp');
var userSchema = new Schema({name:String,password:String});
userModel =db.model('UserList',userSchema);
var userCount = userModel.count('name');
userCount is an Object, which method called can get a real count?
Thanks
The reason your code doesn't work is because the count function is asynchronous, it doesn't synchronously return a value.
Here's an example of usage:
userModel.count({}, function( err, count){
console.log( "Number of users:", count );
})
The code below works. Note the use of countDocuments.
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost/myApp');
var userSchema = new mongoose.Schema({name:String,password:String});
var userModel =db.model('userlists',userSchema);
var anand = new userModel({ name: 'anand', password: 'abcd'});
anand.save(function (err, docs) {
if (err) {
console.log('Error');
} else {
userModel.countDocuments({name: 'anand'}, function(err, c) {
console.log('Count is ' + c);
});
}
});
You should give an object as argument
userModel.countDocuments({name: "sam"});
or
userModel.countDocuments({name: "sam"}).exec(); //if you are using promise
or
userModel.countDocuments({}); // if you want to get all counts irrespective of the fields
For the older versions of mongoose, use
userModel.count({name: "sam"});
The collection.count is deprecated, and will be removed in a future version. Use collection.countDocuments or collection.estimatedDocumentCount instead.
userModel.countDocuments(query).exec((err, count) => {
if (err) {
res.send(err);
return;
}
res.json({ count: count });
});
Background for the solution
As stated in the mongoose documentation and in the answer by Benjamin, the method Model.count() is deprecated. Instead of using count(), the alternatives are the following:
Model.countDocuments(filterObject, callback)
Counts how many documents match the filter in a collection. Passing an empty object {} as filter executes a full collection scan. If the collection is large, the following method might be used.
Model.estimatedDocumentCount()
This model method estimates the number of documents in the MongoDB collection. This method is faster than the previous countDocuments(), because it uses collection metadata instead of going through the entire collection. However, as the method name suggests, and depending on db configuration, the result is an estimate as the metadata might not reflect the actual count of documents in a collection at the method execution moment.
Both methods return a mongoose query object, which can be executed in one of the following two ways. Use .exec() if you want to execute a query at a later time.
The solution
Option 1: Pass a callback function
For example, count all documents in a collection using .countDocuments():
someModel.countDocuments({}, function(err, docCount) {
if (err) { return handleError(err) } //handle possible errors
console.log(docCount)
//and do some other fancy stuff
})
Or, count all documents in a collection having a certain name using .countDocuments():
someModel.countDocuments({ name: 'Snow' }, function(err, docCount) {
//see other example
}
Option 2: Use .then()
A mongoose query has .then() so it’s “thenable”. This is for a convenience and query itself is not a promise.
For example, count all documents in a collection using .estimatedDocumentCount():
someModel
.estimatedDocumentCount()
.then(docCount => {
console.log(docCount)
//and do one super neat trick
})
.catch(err => {
//handle possible errors
})
Option 3: Use async/await
When using async/await approach, the recommended way is to use it with .exec() as it provides better stack traces.
const docCount = await someModel.countDocuments({}).exec();
Learning by stackoverflowing,
Using mongoose.js you can count documents,
count all
const count = await Schema.countDocuments();
count specific
const count = await Schema.countDocuments({ key: value });
The highest voted answers here are perfectly fine I just want to add up the use of await so that the functionality asked for can be achieved:
const documentCount = await userModel.count({});
console.log( "Number of users:", documentCount );
It's recommended to use countDocuments() over 'count()' as it will be deprecated going on. So, for now, the perfect code would be:
const documentCount = await userModel.countDocuments({});
console.log( "Number of users:", documentCount );
Model.count() method is deprecated in mongoose version 6.2.0. If you want to count the number of documents in a collection, e.g. count({}), use the estimatedDocumentCount() function instead. Otherwise, use the countDocuments() function instead.
Model.estimatedDocumentCount() Estimates the number of documents in the MongoDB collection. It is Faster than using countDocuments() for large collections because estimatedDocumentCount() uses collection metadata rather than scanning the entire collection.
Example:
const numAdventures = await Adventure.estimatedDocumentCount();
reference : https://mongoosejs.com/docs/api.html#model_Model.estimatedDocumentCount
As said before, your code will not work the way it is. A solution to that would be using a callback function, but if you think it would carry you to a 'Callback hell', you can search for "Promisses".
A possible solution using a callback function:
//DECLARE numberofDocs OUT OF FUNCTIONS
var numberofDocs;
userModel.count({}, setNumberofDocuments); //this search all DOcuments in a Collection
if you want to search the number of documents based on a query, you can do this:
userModel.count({yourQueryGoesHere}, setNumberofDocuments);
setNumberofDocuments is a separeted function :
var setNumberofDocuments = function(err, count){
if(err) return handleError(err);
numberofDocs = count;
};
Now you can get the number of Documents anywhere with a getFunction:
function getNumberofDocs(){
return numberofDocs;
}
var number = getNumberofDocs();
In addition , you use this asynchronous function inside a synchronous one by using a callback, example:
function calculateNumberOfDoc(someParameter, setNumberofDocuments){
userModel.count({}, setNumberofDocuments); //this search all DOcuments in a Collection
setNumberofDocuments(true);
}

Resources