Skip to content

Commit

Permalink
Optimize model class methods
Browse files Browse the repository at this point in the history
No Issue
- Reorder promise chains to defer database queries until they
  are needed.
- Execute database queries that are not dependent on each other in
  parallel instead of sequentially.
- Reduce the number of variables used to hold state across multiple
  promise blocks.
- Do not go async unless necessary.
  • Loading branch information
jaswilli committed Dec 19, 2014
1 parent 8ceb896 commit 5c6d45f
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 197 deletions.
43 changes: 19 additions & 24 deletions core/server/models/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,7 @@ Post = ghostBookshelf.Model.extend({
findPage: function (options) {
options = options || {};

var postCollection = Posts.forge(),
tagInstance = options.tag !== undefined ? ghostBookshelf.model('Tag').forge({slug: options.tag}) : false,
var tagInstance = options.tag !== undefined ? ghostBookshelf.model('Tag').forge({slug: options.tag}) : false,
authorInstance = options.author !== undefined ? ghostBookshelf.model('User').forge({slug: options.author}) : false;

if (options.limit && options.limit !== 'all') {
Expand Down Expand Up @@ -379,12 +378,6 @@ Post = ghostBookshelf.Model.extend({
options.where.status = options.status;
}

// If there are where conditionals specified, add those
// to the query.
if (options.where) {
postCollection.query('where', options.where);
}

// Add related objects
options.withRelated = _.union(options.withRelated, options.include);

Expand All @@ -405,12 +398,21 @@ Post = ghostBookshelf.Model.extend({
}

return Promise.join(fetchTagQuery(), fetchAuthorQuery())

// Set the limit & offset for the query, fetching
// with the opts (to specify any eager relations, etc.)
// Omitting the `page`, `limit`, `where` just to be sure
// aren't used for other purposes.
.then(function () {
var postCollection = Posts.forge(),
collectionPromise,
countPromise,
qb;

// If there are where conditionals specified, add those
// to the query.
if (options.where) {
postCollection.query('where', options.where);
}
// If we have a tag instance we need to modify our query.
// We need to ensure we only select posts that contain
// the tag given in the query param.
Expand All @@ -431,22 +433,15 @@ Post = ghostBookshelf.Model.extend({
.query('offset', options.limit * (options.page - 1));
}

return postCollection
collectionPromise = postCollection
.query('orderBy', 'status', 'ASC')
.query('orderBy', 'published_at', 'DESC')
.query('orderBy', 'updated_at', 'DESC')
.fetch(_.omit(options, 'page', 'limit'));
})

// Fetch pagination information
.then(function () {
var qb,
tableName = _.result(postCollection, 'tableName'),
idAttribute = _.result(postCollection, 'idAttribute');
// Find the total number of posts

// After we're done, we need to figure out what
// the limits are for the pagination values.
qb = ghostBookshelf.knex(tableName);
qb = ghostBookshelf.knex('posts');

if (options.where) {
qb.where(options.where);
Expand All @@ -460,13 +455,13 @@ Post = ghostBookshelf.Model.extend({
qb.where('author_id', '=', authorInstance.id);
}

return qb.count(tableName + '.' + idAttribute + ' as aggregate');
})
countPromise = qb.count('posts.id as aggregate');

// Format response of data
.then(function (resp) {
var totalPosts = parseInt(resp[0].aggregate, 10),
return Promise.join(collectionPromise, countPromise);
}).then(function (results) {
var totalPosts = parseInt(results[1][0].aggregate, 10),
calcPages = Math.ceil(totalPosts / options.limit) || 0,
postCollection = results[0],
pagination = {},
meta = {},
data = {};
Expand Down
59 changes: 26 additions & 33 deletions core/server/models/tag.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var _ = require('lodash'),
Promise = require('bluebird'),
errors = require('../errors'),
ghostBookshelf = require('./base'),
sitemap = require('../data/sitemap'),
Expand Down Expand Up @@ -73,7 +74,10 @@ Tag = ghostBookshelf.Model.extend({
options = options || {};

var tagCollection = Tags.forge(),
tagTotal;
collectionPromise,
totalPromise,
countPromise,
qb;

if (options.limit && options.limit !== 'all') {
options.limit = parseInt(options.limit, 10) || 15;
Expand All @@ -98,43 +102,32 @@ Tag = ghostBookshelf.Model.extend({
.query('offset', options.limit * (options.page - 1));
}

return tagCollection
.fetch(_.omit(options, 'page', 'limit'))
// Fetch pagination information
.then(function () {
var qb,
tableName = _.result(tagCollection, 'tableName'),
idAttribute = _.result(tagCollection, 'idAttribute');
collectionPromise = tagCollection.fetch(_.omit(options, 'page', 'limit'));

// After we're done, we need to figure out what
// the limits are for the pagination values.
qb = ghostBookshelf.knex(tableName);
// Find total number of tags

if (options.where) {
qb.where(options.where);
}
qb = ghostBookshelf.knex('tags');

return qb.count(tableName + '.' + idAttribute + ' as aggregate');
})
// Fetch post count information
.then(function (resp) {
var qb;
tagTotal = resp;
if (options.where) {
qb.where(options.where);
}

if (options.include) {
if (options.include.indexOf('post_count') > -1) {
qb = ghostBookshelf.knex('posts_tags');
totalPromise = qb.count('tags.id as aggregate');

return qb.select('tag_id').count('* as postCount').groupBy('tag_id');
}
} else {
return null;
// Fetch post count information

if (options.include) {
if (options.include.indexOf('post_count') > -1) {
qb = ghostBookshelf.knex('posts_tags');
countPromise = qb.select('tag_id').count('* as postCount').groupBy('tag_id');
}
})
// Format response of data
.then(function (postsPerTagCollection) {
var totalTags = parseInt(tagTotal[0].aggregate, 10),
}

return Promise.join(collectionPromise, totalPromise, countPromise).then(function (results) {
var totalTags = results[1][0].aggregate,
calcPages = Math.ceil(totalTags / options.limit) || 0,
tagCollection = results[0],
postsPerTagCollection = results[2],
pagination = {},
meta = {},
data = {};
Expand All @@ -148,12 +141,12 @@ Tag = ghostBookshelf.Model.extend({

data.tags = tagCollection.toJSON();

if (postsPerTagCollection !== null) {
if (postsPerTagCollection) {
// Merge two result sets
_.each(data.tags, function (tag) {
var postsPerTag = _.find(postsPerTagCollection, function (obj) { return obj.tag_id === tag.id; });
if (postsPerTag) {
tag.post_count = parseInt(postsPerTag.postCount, 10);
tag.post_count = postsPerTag.postCount;
} else {
tag.post_count = 0;
}
Expand Down
Loading

0 comments on commit 5c6d45f

Please sign in to comment.