Moongoose sort by parseFloat(String)? - node.js

I want to sort my query result by the Float value. But the value stored in MongoDB is type String, Can I parse the String to Float and sort it dynamically? Just like complex sort.
The following are parts of my schema and sort code:
Schema:
var ScenicSpotSchema = new Schema({
...
detail_info: {
...
overall_rating: String,
...
},
});
Sort function:
ScenicSpot.find({'name': new RegExp(req.query.keyword)}, )
.sort('-detail_info.overall_rating')
.skip(pageSize * pageNumber)
.limit(pageSize)
.exec(function (err, scenicSpots) {
if (err) {
callback(err);
} else {
callback(null, scenicSpots);
}
});
Any kind of help and advice is appreciated. :)

.sort mongoose do not support converting data type. see: http://mongoosejs.com/docs/api.html#query_Query-sort
It only accept column names and order.
There are two path to acheive your goal:
use mapreduce in mongo, first convert type, and the sort
retrieve all data from database, and sort it in your node.js program.
But both are terrible and ugly
if you wanna sort a String column but parse it as Float. This action would scan all data in that collection, and can not use index. It's very very slow action.
So I think the fastest and correct operation is convert the String column to Float in your mongodb database. And then you can use normal .sort('-detail_info.overall_rating') to get things done.

user collation after sort query it will sort string float number in ascending and descending order both correctly.
cenicSpot.find({'name': new RegExp(req.query.keyword)}, )
.sort('-detail_info.overall_rating')
.collation({ locale: "en-US", numericOrdering: true })
.skip(pageSize * pageNumber)
.limit(pageSize)
.exec(function (err, scenicSpots) {
if (err) {
callback(err);
} else {
callback(null, scenicSpots);
}
});

Related

get Data from a collection in MongoDB using NodeJS

I am trying to get data from Mongo DB by filtering a nested object.
the collection structure is :
{
"id":"8820624457",
"type":"CreateEvent",
"actor":{
"id":27394937,
"login":"Johnson0608",
"display_login":"Johnson0608",
"gravatar_id":"",
"url":"https://api.github.com/users/Johnson0608",
"avatar_url":"https://avatars.githubusercontent.com/u/27394937?"
},
"repo":{
"id":163744671,
"name":"Johnson0608/test",
"url":"https://api.github.com/repos/Johnson0608/test"
},
"payload":{
"ref":"master",
"ref_type":"branch",
"master_branch":"master",
"description":null,
"pusher_type":"user"
},
"public":true,
"created_at":"2019-01-01T15:00:00Z"
}
I am trying to get data by repo id.
my code is :
collection.find({'repo.id':id}).toArray(function(err, docs) {
console.log(id);
assert.equal(err, null);
console.log("Found the following records");
console.log(docs);
res.status(200).json({docs});
callback(docs);
});
but I am getting empty array, would be grateful is someone can point me to the right direction
MongoDB compares types before values. If your id comes from req.params it's probably passed as string while repo.id seems to be a number. Try to convert your value to number:
const id = +req.params.repoId

How to define a sort function in Mongoose

I'm developing a small NodeJS web app using Mongoose to access my MongoDB database. A simplified schema of my collection is given below:
var MySchema = mongoose.Schema({
content: { type: String },
location: {
lat: { type: Number },
lng: { type: Number },
},
modifierValue: { type: Number }
});
Unfortunately, I'm not able to sort the retrieved data from the server the way it is more convenient for me. I wish to sort my results according to their distance from a given position (location) but taking into account a modifier function with a modifierValue that is also considered as an input.
What I intend to do is written below. However, this sort of sort functionality seems to not exist.
MySchema.find({})
.sort( modifierFunction(location,this.location,this.modifierValue) )
.limit(20) // I only want the 20 "closest" documents
.exec(callback)
The mondifierFunction returns a Double.
So far, I've studied the possibility of using mongoose's $near function, but this doesn't seem to sort, not allow for a modifier function.
Since I'm fairly new to node.js and mongoose, I may be taking a completely wrong approach to my problem, so I'm open to complete redesigns of my programming logic.
Thank you in advance,
You might have found an answer to this already given the question date, but I'll answer anyway.
For more advanced sorting algorithms you can do the sorting in the exec callback. For example
MySchema.find({})
.limit(20)
.exec(function(err, instances) {
let sorted = mySort(instances); // Sorting here
// Boilerplate output that has nothing to do with the sorting.
let response = { };
if (err) {
response = handleError(err);
} else {
response.status = HttpStatus.OK;
response.message = sorted;
}
res.status(response.status).json(response.message);
})
mySort() has the found array from the query execution as input and the sorted array as output. It could for instance be something like this
function mySort (array) {
array.sort(function (a, b) {
let distanceA = Math.sqrt(a.location.lat**2 + a.location.lng**2);
let distanceB = Math.sqrt(b.location.lat**2 + b.location.lng**2);
if (distanceA < distanceB) {
return -1;
} else if (distanceA > distanceB) {
return 1;
} else {
return 0;
}
})
return array;
}
This sorting algorithm is just an illustration of how sorting could be done. You would of course have to write the proper algorithm yourself. Remember that the result of the query is an array that you can manipulate as you want. array.sort() is your friend. You can information about it here.

Values of the results object is null when quering a database in node.js

So I'm trying to query a record from a database and then put it into xml format in node.js. The programname is the primary key of the sasinfo table, so it's guaranteed that I'll only be working with one record. The problem is that when I run the code below, console.log(messagetoclient) prints this:
<messagetoclient><programname>undefined</programname><comment>undefined</comment><guid>undefined</guid></messagetoclient>
However, console.log(results) prints the this (the correct values from the record):
[ { programname: 'helloworld',
comment: 'testing',
GUID: '9b23e0f7b7da4535b99f706301539a44' } ]
Could someone help me figue out why the values of the key value pairs aren't being printed? Thanks.
query2 = connection.query('SELECT * FROM sasinfo WHERE programname = ?', [programname], function(err, results) {
if(err){
console.log(err);
}
else{
console.log(results);
messagetoclient= '<messagetoclient><programname>'+results.programname+'</programname><comment>'+results.comment+'</comment><guid>'+results.GUID+'<guid></messagetoclient>';
console.log(messagetoclient);
}
});
Try
messagetoclient= '<messagetoclient><programname>'+results[0].programname+'</programname><comment>'+results[0].comment+'</comment><guid>'+results[0].GUID+'<guid></messagetoclient>';
since results is an array.

how to improve the view with map/reduce in couchdb and nodejs

I'm using nodejs with the module cradle to interact with the couchdb server, the question is to let me understanding the reduce process to improve the view query...
For example, I should get the user data from his ID with a view like this:
map: function (doc) { emit(null, doc); }
And in node.js (with cradle):
db.view('users/getUserByID', function (err, resp) {
var found = false;
resp.forEach(function (key, row, id) {
if (id == userID) {
found = true;
userData = row;
}
});
if (found) {
//good, works
}
});
As you can see, this is really bad for large amount of documents (users in the database), so I need to improve this view with a reduce but I don't know how because I don't understand of reduce works.. thank you
First of all, you're doing views wrong. View are indexes at first place and you shouldn't use them for full-scan operations - that's ineffective and wrong. Use power of Btree index with key, startkey and endkey query parameters and emit field you like to search for as key value.
In second, your example could be easily transformed to:
db.get(userID, function(err, body) {
if (!err) {
// found!
}
});
Since in your loop you're checking row's document id with your userID value. There is no need for that loop - you may request document by his ID directly.
In third, if your userID value isn't matches document's ID, your view should be:
function (doc) { emit(doc.userID, null); }
and your code will be looks like:
db.view('users/getUserByID', {key: userID}, function (err, resp) {
if (!err) {
// found!
}
});
Simple. Effective. Fast. If you need matched doc, use include_docs: true query parameter to fetch it.

How to query data from different collections and sort by date?

I stumbled upon problem that my search results are of a mixed data, which is located in different collections (posts/venues/etc), currently Im doing separate requests to retrieve this data, but its obviously sorted among its types (posts array, venues array)
How can I query multiple collections (posts/venues) and sort them by date/any other parameter (via mongoose)?
or maybe there is a better solution?
Thanks
I believe its not possible with Mongoose, you can in the meanwhile do something like this:
var async = require('async');
function getPosts(cb) {
Post.find({"foo": "bar"}, function(err, posts) {
cb(err, posts);
})
}
function getVenues(cb) {
Venue.find({"foo": "bar"}, function(err, venues) {
cb(err, venues);
})
}
async.parallel([getPosts, getVenues], function(err, results) {
if(err) {
next(err);
}
res.send(results.sort(function(a, b) {
//if default sorting is not enough you can change it here
return a.date < b.date ? -1 : a.date > b.date ? 1 : 0;
}));
});
This code assumes you are inside an express route and that both Posts and Venues have a common attribute; date. In case you named these dates attributes differently you would have to improve the sort algorithm.

Resources