Mongoose, AngularJS, NodeJS - node.js

I am using a MongoDB database.
For the front AngularJS.
Also, I am using Mongoose.
I have:
app.get("/images", function(req, res) {
mongoose.model('Image').find(function (err, images) {
res.send(images);
});
});
app.listen(3000);
It works fine when I go to: http://localhost:3000/images
then:
<div ng-repeat="photo in photos">
<!-- My Data List -->
<h3>{{photo.name}}</h3>
</div>
Until here, everything is fine.
BUT I will have like thousand and thousand data to display.
So I will need something like "infinite scroll" for the front and also I will need to limit the API http://localhost:3000/images with query range or pagination ???
How I can proceed to do something with lots of data?
Thanks!

You likely don't want to load all data at once if it is a huge amount.
First I would do something like this limit the number of entries you get for each request.
app.get("/images", function(req, res) {
var query = mongoose.model('Image').find({})
.limit(req.query.numberOfItems)
.skip(req.query.index)
query.exec(function (err, images) {
res.send(images);
});
});
app.listen(3000);
On the client you should then decide to dynamically load more data once you need it.
This depends a little bit on what you want the user experience to be e.g have different pages and you load more data once you open the next page or if the user scrolls down further etc.

Use server side pagination in mongoose using mongoose-paginate and limit your query output. Same way to include pagination in angular use angular-ui pagination. If you want to use the infinite scroll then in angular use ngInfiniteScroll.
Hope this helps.

You can use the mongoose Query API to specify conditions on which to search: http://mongoosejs.com/docs/queries.html
You can use where() to specify you pagination criteria, e.g., where({id: {$gt: page}}) (assuming you are using some kind of auto-incrementing id) and limit() to specify your page size, e.g., limit(10).
Each time you query the server for an additional page, you will need to supply the criteria in your URL: /images?page=1. This criteria should be incremented by 10 each time you fetch a page.
The criteria can be anything that represents a sequential ordering of your data, whether an ID, or a timestamp, or some other arbitrary value.

To limit the data in mongoose:
mongoose.model('Image').limit(10).exec(function(err, images){
// get the images....
}); // this will only return 10 images
While in angular you can use limitTo filter:
<div ng-repeat="photo in photos | limitTo: 10 ">
<!-- My Data List -->
<h3>{{photo.name}}</h3>
</div>
Now from here you can learn how to paginate or infinit scroll. (There are various tuts on this topic on the web)

Related

Contentful: How to get an entry using nothing but one of its fields? Or, how to set the entryId in web app?

I am needing to make some sharable blog post URLs. To do that, the URL must be something like webpage.com/blog-post-title. It cannot be webpage.com/5GFd5GDSg2345WD.
Since I am using dynamic routing, I need to get a Contentful entry using nothing but what is on the URL. There should not be any queries because queries are ugly and reduce shareability, like webpage.com/blog-post-title?query=queriesAreUgly.
Unfortunately, I need the entryId to get the entry. Also unfortunately, the entryIds are all very ugly and therefore completely useless/unusable. I wish I could set my own entryId, but this does not appear to be possible for mysterious reasons.
I could make a lookup table that pairs URLs with entryIds, but I'm going to be handing this contentful project to someone who is not tech savy, and they should not have to manage a lookup table.
I could get all blog entries then filter by blog title, but, very obviously, this is inefficient, as I would be loading thousands of lines of text for no reason at all.
I could create my own backend API and doing all this myself, but this is also a bad solution because it would take too much time and I could not give it to my non-tech-savvy client.
There are seemingly no solutions to this problem which created by Contentful's inherent needless inflexibility.
The only efficient way to get this to work is to find the entry not by its ID but by one of its fields. Is there a performant/efficient way to do this, or am I just going to have to filter through every single blog post until I find the one with the correct title?
How about adding a 'slug' field to the blog post content type, which you can auto-generate from the title using the field settings (so you don't have to type it out manually?)
You can then filter on the slug field in the query.
If you're using the JavaScript SDK (which it sounds like you are), you can use getEntries() and filter by the slug field to get a single blog post. Like so:
import { createClient } from "contentful";
const client = createClient({
space: {SPACE_ID},
accessToken: {ACCESS_TOKEN},
});
const response = await client
.getEntries({
content_type: "blogPost",
limit: 1,
"fields.slug": "blog-post-title",
})
.then((entry) => entry)
.catch(console.error);

How to make mongodb and nodejs response fast?

I have a blog schema(title, topic, body, author, etc) and a function to return all the blogs in that document.
Right now I am just doing Blog.find() to pull all the data at once and sending the responses using res.send(). The problem is the body property of the blog is very large and it takes a lot of time to return the results.
Is there any way to make it fast.
You can get faster results if you add the fields you use the most in searches to the collection as an index.
Usage example:
//The following example creates a single key descending index on the name field:
db.collection.createIndex( { name: -1 } )

Remove record based on id passed in the url using mongoose with mongodb in a handlebars project

I have a handlebars/express/mongodb project where I am able to save and create users who can save and create a trip itinerary. I am trying to remove (delete) a particular itinerary. I have a user model and a trip model in a one to many relationship. The front end uses handlebars as the template. I am able to save multiple trips for the same user and display them. I am trying to delete one trip based on its id passed through the url. The trip, of course, has a unique id as assigned by mongodb.
My front end handlebars code looks like this and is a handlebars partial:
<form action="trips/itinerary/delete/{{this._id}}?_method=DELETE" method="POST">
<button type="submit" class="submit">DELETE!</button>
</form>
My js code using mongoose to remove in my logic file (where creating new trips and rendering them is working just fine) looks like this:
router.delete('/delete/:_id', function(req,res) {
Trip.remove(
{ _id: req.params._id }
)
// connect it to this .then.
.then(function() {
res.redirect('/itinerary');
})
});
I am getting a not found error, although it is throwing the trip _id into the url. I am thinking the issue is with my use of params? I cannot seem to find a clear example of how to do this using all the tools I am using in this project.
Thanks in advance for any suggestions or help!
You need to convert the id from the client to a valid ObjectId, or use findByIdAndRemove function, this function accepts a String, a ObjectId or a numebr so is more easy to use.
http://mongoosejs.com/docs/api.html#model_Model.findByIdAndRemove

The "right way" to load, crunch and pass variables from Express to Jade

I'm building an app in Express. In one of the views a logged in Superadmin is able to view all available clients/user. In this view I am loading a bunch of client data from my MongoDB/Mongoose with a simple:
app.get('/superadmin', function(req, res) {
Client.find({}, '_id company monthly_cost sms_cost', function (err, docs) ...
As you can see above i have choosen only the values that I need from the query. These four are: "_id", "company", "monthly_cost" and "sms_cost"
From the "_id" i can get a "creation date" by using .getTimestamp(), but the Dateobject this function return is bit to complex formated. I need a simpler date, something like: (YYYY-MM-DD). Im thinking of using a small node plugin like dateformat or possibly writing a very simple function that extract the YYYY, MM and DD from the IsoDate object and saving this in a new variable/array
Now to my questions:
Q1) WHERE is actually the right place for this code? I'm currently putting it inside the route handler above... consequently it will follow right below the code above. I'm thinking this is principally the right way according to a MVC pattern. I'm thinking I dont want to put this code in the Jade view template?
Q2) IN WHAT FORM should i save this data and HOW should i pass it along to Jade. Should I somehow add it to the "docs"-data... that is, the data I extract from my DB. Or should I rather put this creationDate in a separate array which i pass to jade side by side with the original DB-data.
I hope my questions are clear enough!
Q1:
If your Mongoose-query is solely dependent on your route /superadmin, this is exactly the right place to put your code. If you are using the same snippet in different routes or functions you might as well wrap it in a function that is accessible to every route in question. But donĀ“t forget to also wrap req, res and other required variables. Have your calculations within your callback and use Jade only for representation of data.
Q2:
What do you mean by "save"? When you are already iterating over every document to do your calculations and transformations, create an extra field creationDate for every document and pass docs as a single parameter to the Jade file afterwards.

ember.js rest api with pagination

At the moment I'm pointless how do achieve pagination with ember-data. I found out, that i can return 'meta' property in response and ember-data does not throw an error. But I just don't know how to access it, nor what is intended purpose of this property.
The few examples on internet assume that i have whole collection already loaded to ember, or they do little trick and do infinite scroll, which does'nt require information about page count.
I think that loading all records it's ok if I would have < 1k of them, but sometimes I'll be dealing with massive amounts of data (let's say apache logs). What then?
So basically I'm at the point in which I would like to use ember and ember-data to build my first real-life application, but I just think that it is not a good idea.
Ok, so anybody has any idea how to solve this basic, yet complicated, problem? :)
Ok, so here are some ideas to get you started.
First, you have to start with a route and take an page number as a dynamic parameter.
this.resource('posts', { path: '/posts/:page' };
Then as I have no experience with Silex, you need to support some kind of server side parameters that could be used for pagination. For example offset and limit where first means how many records you want to skip and second how many record you want in select from there. Ideally you should implement them as query parameters like ?offset=0&limit=10.
Then you just implement your table route as follows:
App.TableRoute = Ember.Route.extend({
model: function (params) {
return App.Post.find({ offset: (params.page - 1) * 10, limit: 10 });
}
});
You can then start doing some more magic and create your items per page parameter or validate the page number by fetching number of all records in advance.

Resources