mongoose pagination - javascript

I'm trying to make an easy pagination for a REST service with MongoDB and Mongoose. Here's how I'm doin it right now.
As you can see I'm sending 0 on 'next' variable, but I just want to send zero when there are no more results. How could I get when results are over and there are no more to get?
var user = User.find(
{},
{},
{skip: skip, limit: limit},
function(err, docs) {
if (!err) {
res.json({users: docs, next: 0} );
} else {
throw err;
}
});
Thanks!
PS: I'm using node.js and express.

Try this:
if ( !docs ) {
res.json({users: [], next: 0});
}

if i got your question right you would like to send the ammount of remaining documents for the next query, if so you could query with limit * 2 but only return 'limit' documents, substract limit from docs.length and you will get the ammount of remaining documents for the next query.
there may be a better solution with a more adanvced query.

Related

Need some help regarding the Elasticsearch engine and react js

I hope you are doing well, I need some help regarding the Elasticsearch engine. what I am doing is I am trying to create a search engine I have successfully post my data through kibana to elasticsearch engine. but "but how can I add the search component of elastyicsearch to my react app", I have like 4 million records into the kibana index, when I try to search directly from react it take a long time to display records into my frontapp app with nodejs api. below is the code with nodejs but the problem with this code it just gives me 10 records only.
router.get('/tweets', (req, res)=>{
let query = {
index: 'tweets',
// size: 10000
}
if(req.query.tweets) query.q = `*${req.query.tweets}*`;
client.search(query)
.then(resp => {
return res.status(200).json({
tweets: resp.body.hits.hits
});
})
.catch(err=>{
console.log(err);
return res.status(500).json({
err
});
});
});
Is there any way to impliment elasticsearch component directly to my reactjs app. like with the localhost:9200/index.. directly from the elasticsearch api?
Your request to Elasticsearch looks a bit strange to me, have you tried to search using a body like in the documentation? This line:
if(req.query.tweets) query.q = `*${req.query.tweets}*`;
doesn't seem like a correct way to write a query. Which field do you want to search for?
I saw that you tried to use the size field, which should be correct. You can also try the following:
client.search({
index: 'tweets',
body: {
size: 1000, // You can put the size here to get more than 10 results
query: {
wildcard: { yourfield: `*${req.query.tweets}*` }
}
}
}, (err, result) => {
if (err) console.log(err)
})
You could use SearchKit to directly query elasticsearch from you react app. But be aware that exposing DB services outside of your own infrastructure is bad practice.
You can use the component like this:
import {
SearchkitManager,
SearchkitProvider,
SearchkitComponent
} from 'searchkit'
const searchkit = new SearchkitManager(host)
class Render extends SearchkitComponent {
render(){
let results = await this.searchkit.reloadSearch()
return <div>{results}</div>
}
}
function table(){
return <SearchkitProvider searchkit={searchkit}>
<Render />
</SearchkitProvider>
}

Mongodb, how to multiple request to aliment 1 object

i'm creating a forum, and i want to get the number of message in one topic,
so in my method GetListTopic i get the list of topic, and after i want to know how many message there is in one topic so i request the table forum_message for every topic in my list=>
db.Forum_Topic.count({}, function (err, topicount) { //nombre de topic
db.Forum_Topic.find().skip(skipNumber).limit(nombreDeTopicParPage).sort({ dateLastMessage: -1 }, function (err, dbres) {
//dbres = liste de topic
for (var i in dbres)
{
db.Forum_Message.count({ idTopic: new mongojs.ObjectID(dbres[i]._id) }, function (err, Messagecount) {
dbres[i].TotalMessage = Messagecount;
});
}
res.send([dbres, topicount]);
});
});
my need is to add in every object of my list the total message => dbres[i].TotalMessage = Messagecount;
but that don't work dbres[i].TotalMessage is set correctly in the function callback but when i send object TotalMessage doesn't exist ....
someone can help me please ?
The problem is that you are using for loop within an async function. And that res.send() statement does not wait for the loop to complete. It executes before.
There is a solution by using this async library. There are also many options in this library, however, I think the async.each() is the one you can try.
Good luck.
i finally found the solution to foreach update with nodejs and mongodb,
i use async.js here : https://www.npmjs.com/package/async
and to delete a liste of mail
async.each(ListeIdMailToDelete, function (mailID, callback) {
db.userMessageMail.find({ _id: db.ObjectId(mailID) }, function (err, dbres) {
if (dbres.length > 0)
{
if (dbres[0].expediteur == newplayer.pseudo || dbres[0].destinataire == newplayer.pseudo) {
db.userMessageMail.remove({ _id: dbres[0]._id }, function () {
callback(err);
})
}
}
});
}, function (err) {
console.log(err);
});

Meteor getting double insert on mongo database

The following code is an event to gathering information regarding expenses and done tasks into a bills database. Everytime I run this process I'm getting 2 entries into the bills database. The first entry is always empty and the second one has the entries I want.
'click .ConfirmCloseCase': function (event) {
var caseID = Session.get('CurrentClosingCaseID');
var TasksToChange = Tasks.find({caseID:caseID,done:true,billed:false});
var ExpensesToChange = Expenses.find({caseID:caseID,billed:false});
// Create new Entry into bills Database
Bills.insert({"expensestotal":0,"taskstotaltime":0}, function(error, result) {
// Set all Tasks to billed
TasksToChange.forEach(function(task){
Tasks.update(task._id, {$set: {"billed": true} })
Meteor.call( 'BillsUpsert', result, {$push: {"tasks": task._id}} );
Meteor.call( 'BillsUpsert', result, {$inc: {"taskstotaltime": task.hours}} );
})
// Set all Expenses to billed
ExpensesToChange.forEach(function(expense){
Expenses.update(expense._id, {$set: {"billed": true} })
Meteor.call( 'BillsUpsert', result, {$push: {"expenses": expense._id}} );
Meteor.call( 'BillsUpsert', result, {$inc: {"expensestotal": expense.amount}} );
})
Router.go('/Bills');
})
},
The Meteor call is like so:
Meteor.methods({
BillsUpsert: function( id, doc ){
Bills.update( id, doc );
}
});
My guess it that I'm getting 2 entries into the database is because the code is running asynchronously. Is this a correct assumption?... and as a followup is there an "easy" fix? :)
I don't think the asynchronous calls are the root cause of your problem but you can significantly simplify this code by moving all your inserts and updates to the server:
'click .ConfirmCloseCase': function (event) {
Meteor.call('closeCase',Session.get('CurrentClosingCaseID'),function(err,result){
if ( err ){
// handle error
} else {
Router.go('/Bills');
}
});
}
Method:
Meteor.methods({
closeCase: function(caseId){
// you need to implement security checks on caseId here!
// Synchronously create new document in Bills collection
var billId = Bills.insert({ expensestotal: 0, taskstotaltime:0 });
// Set all Tasks to billed
var TasksToChange = Tasks.find({ caseID: caseID, done: true, billed: false });
TasksToChange.forEach(function(task){
Tasks.update(task._id, {$set: { billed: true} });
Bills.update(billId,{ $push: { tasks: task._id }, $inc: { taskstotaltime: task.hours }} );
)};
// Set all Expenses to billed
var ExpensesToChange = Expenses.find({ caseID: caseID, billed: false});
ExpensesToChange.forEach(function(expense){
Expenses.update(expense._id, {$set: { billed: true} });
Bills.update(billId,{ $push: { expenses: expense._id }, $inc: { expensestotal: expense.amount }} );
)};
}
After much trial and error I found the problem. The double entry into my database was not related to the code I posted and was due to a stupid mistake of my part of calling the function twice from two different places in my code.
Sorry for wasting people's time with this post.

Setting a server variable to data held in a mongo collection Meteor.js

For my application, I have to make an HTTP.call to get a session ID. I need to store this session ID into a mongo collection, which I am doing like this.
if (Meteor.isServer) {
sessionDB = new Mongo.Collection("sessionID");
HTTP.call( 'GET', 'http://mycalltosomeapi.svc/json/whatever', {
}, function( error, response ) {
if ( error ) {
console.log(error);
} else {
sessionDB.insert({
sessionId: response.data.session_id,
date_inserted: new Date()
});
}
}
how do I grab the most recent entry of my mongo stored 'sessionId' and put that into a variable so I can make other calls? I tried doing it like this but had no luck.
var sessionId = sessionDB.findOne({}, {sessionId:1}).sort({"date_inserted":-1}).limit(1);
Been researching for a couple hours now, can't find anything. Thanks in advance
sort and limit are options to find and findOne. Give this a try:
var options = {
fields: {sessionId: 1},
sort: {date_inserted: -1}
};
var sessionId = sessionDB.findOne({}, options);

RangeError when trying to execute mongodb query with mongoose/mongodb-native

I have a problem which has already cost me a couple of days and I totally fail to understand it. I use node.js and have a mongodb with places indexed for their coordinates. I verified that the index works fine beforehand. For a set of coordinates, I want to find the nearest place. Here's how I tried to go about it:
var Places = require(./models/places.js),
coordFinder = require('./coordFinder.js');
...
function getCoords(userId, callback) {
coordFinder.getCoords(userId, function(err, coords) {
if (err) {
callback(err);
} else {
callback(null, coords);
}
}
}
function getNearestPlaces(coords, callback) {
async.forEachSeries(
coords,
function(coord, done) {
Places.findOne(
{ coordinates: { $near: [ coord.lat, coord.lon ] } },
function(err, place) {
// do something with place
done();
}
)
},
function(err) {
callback(err ? err : null);
}
);
}
...
async.waterfall(
[
...
getCoords,
getNearestPlaces,
...
],
function(err) {
...
}
}
The mongodb query consistently fails with the following error message for the first query:
RangeError: Maximum call stack size exceeded
When I change the query in getNearestPlaces to
... { $near: [ 10, 10 ] } ...
I as consistently get no error and the correct place. The same happens if I avoid the call to coordFinderin getCoords and change getCoords to
function getCoords(userId, callback) {
callback(
null,
[
// some coordinates
]
);
I know the error indicates a stack overflow (increasing the stack size didn't help) but I can't figure out how I could have caused one. Does anyone have a clue as to why this happens? Thanks in advance for your insights!
Edit: It got the same problem when using mongodb-native directly, by the way, so mongoose seems not to be the problem. One more clue - using the same query never gives me a problem when I don't call it from within a callback. Could that be a source of error?
I use
node.js 0.6.14
mongodb 2.2.2
node module async 0.1.22
node module mongodb 1.2.5
node module mongoose 2.5.7
Cheers,
Georg
The problem is most likely coming from the hidden recursion of async.forEachSeries. Try wrapping the Places.findOne call with setTimeout like this:
function getNearestPlaces(coords, callback) {
async.forEachSeries(
coords,
function(coord, done) {
setTimeout(function () {
Places.findOne(
{ coordinates: { $near: [ coord.lat, coord.lon ] } },
function(err, place) {
// do something with place
done();
}
);
}, 1);
},
function(err) {
callback(err ? err : null);
}
);
}
This puts the Places.findOne call outside of the call stack of async.forEachSeries.
mjhm pointed me in the right direction. Apparently, the Number instanced passed to the mongoose query caused the stack overflow. I'm not sure why, but creating a new Number object from the old one (as mjhm suggested) or converting the number into a primitive with valueOf() solved the problem.
If anyone has a clue as to how the original Number object caused the stack overflow, I'd very much appreciate any insights you might have to offer.

Categories

Resources