Merge pull request #110 from jorilallo/queryperf

Query Improvements
This commit is contained in:
Jori Lallo 2017-07-06 23:22:16 -07:00 committed by GitHub
commit e82639c828
10 changed files with 100 additions and 115 deletions

View File

@ -18,7 +18,7 @@ class DocumentViewersStore {
this.isFetching = true;
try {
const res = await client.get(
const res = await client.post(
'/views.list',
{
id: this.documentId,

View File

@ -1,13 +1,13 @@
require('./init');
var app = require('./server').default;
var http = require('http');
const app = require('./server').default;
const http = require('http');
var server = http.createServer(app.callback());
const server = http.createServer(app.callback());
server.listen(process.env.PORT || '3000');
server.on('error', (err) => {
server.on('error', err => {
throw err;
});
server.on('listening', () => {
var address = server.address();
console.log('Listening on %s%s', address.address, address.port);
});
const address = server.address();
console.log(`Listening on http://localhost:${address.port}`);
});

View File

@ -24,7 +24,7 @@ router.post('collections.create', auth(), async ctx => {
});
ctx.body = {
data: await presentCollection(ctx, atlas, true),
data: await presentCollection(ctx, atlas),
};
});
@ -33,7 +33,7 @@ router.post('collections.info', auth(), async ctx => {
ctx.assertPresent(id, 'id is required');
const user = ctx.state.user;
const atlas = await Collection.findOne({
const atlas = await Collection.scope('withRecentDocuments').findOne({
where: {
id,
teamId: user.teamId,
@ -43,7 +43,7 @@ router.post('collections.info', auth(), async ctx => {
if (!atlas) throw httpErrors.NotFound();
ctx.body = {
data: await presentCollection(ctx, atlas, true),
data: await presentCollection(ctx, atlas),
};
});
@ -58,16 +58,10 @@ router.post('collections.list', auth(), pagination(), async ctx => {
limit: ctx.state.pagination.limit,
});
// Collectiones
let data = [];
await Promise.all(
collections.map(async atlas => {
return data.push(await presentCollection(ctx, atlas, true));
})
const data = await Promise.all(
collections.map(async atlas => await presentCollection(ctx, atlas))
);
data = _.orderBy(data, ['updatedAt'], ['desc']);
ctx.body = {
pagination: ctx.state.pagination,
data,

View File

@ -8,7 +8,6 @@ import { presentDocument } from '../presenters';
import { Document, Collection, Star, View } from '../models';
const router = new Router();
router.post('documents.list', auth(), pagination(), async ctx => {
let { sort = 'updatedAt', direction } = ctx.body;
if (direction !== 'ASC') direction = 'DESC';
@ -19,9 +18,12 @@ router.post('documents.list', auth(), pagination(), async ctx => {
order: [[sort, direction]],
offset: ctx.state.pagination.offset,
limit: ctx.state.pagination.limit,
include: [{ model: Star, as: 'starred', where: { userId: user.id } }],
});
let data = await Promise.all(documents.map(doc => presentDocument(ctx, doc)));
const data = await Promise.all(
documents.map(document => presentDocument(ctx, document))
);
ctx.body = {
pagination: ctx.state.pagination,
@ -42,7 +44,7 @@ router.post('documents.viewed', auth(), pagination(), async ctx => {
limit: ctx.state.pagination.limit,
});
let data = await Promise.all(
const data = await Promise.all(
views.map(view => presentDocument(ctx, view.document))
);
@ -60,12 +62,17 @@ router.post('documents.starred', auth(), pagination(), async ctx => {
const views = await Star.findAll({
where: { userId: user.id },
order: [[sort, direction]],
include: [{ model: Document }],
include: [
{
model: Document,
include: [{ model: Star, as: 'starred', where: { userId: user.id } }],
},
],
offset: ctx.state.pagination.offset,
limit: ctx.state.pagination.limit,
});
let data = await Promise.all(
const data = await Promise.all(
views.map(view => presentDocument(ctx, view.document))
);
@ -94,8 +101,7 @@ router.post('documents.info', auth(), async ctx => {
ctx.body = {
data: await presentDocument(ctx, document, {
includeCollection: document.private,
includeCollaborators: true,
includeViews: true,
}),
};
});
@ -108,16 +114,8 @@ router.post('documents.search', auth(), async ctx => {
const documents = await Document.searchForUser(user, query);
const data = [];
await Promise.all(
documents.map(async document => {
data.push(
await presentDocument(ctx, document, {
includeCollection: true,
includeCollaborators: true,
})
);
})
const data = await Promise.all(
documents.map(async document => await presentDocument(ctx, document))
);
ctx.body = {
@ -200,11 +198,7 @@ router.post('documents.create', auth(), async ctx => {
}
ctx.body = {
data: await presentDocument(ctx, newDocument, {
includeCollection: true,
includeCollaborators: true,
collection: ownerCollection,
}),
data: await presentDocument(ctx, newDocument),
};
});
@ -230,11 +224,7 @@ router.post('documents.update', auth(), async ctx => {
}
ctx.body = {
data: await presentDocument(ctx, document, {
includeCollection: true,
includeCollaborators: true,
collection: collection,
}),
data: await presentDocument(ctx, document),
};
});
@ -273,11 +263,7 @@ router.post('documents.move', auth(), async ctx => {
}
ctx.body = {
data: await presentDocument(ctx, document, {
includeCollection: true,
includeCollaborators: true,
collection: collection,
}),
data: await presentDocument(ctx, document),
};
});

View File

@ -1,9 +1,10 @@
// @flow
import debug from 'debug';
const debugCache = debug('cache');
export default function cache() {
return async function cacheMiddleware(ctx, next) {
return async function cacheMiddleware(ctx: Object, next: Function) {
ctx.cache = {};
ctx.cache.set = async (id, value) => {

View File

@ -60,6 +60,16 @@ const Collection = sequelize.define(
as: 'documents',
foreignKey: 'atlasId',
});
Collection.addScope('withRecentDocuments', {
include: [
{
as: 'documents',
limit: 10,
model: models.Document,
order: [['updatedAt', 'DESC']],
},
],
});
},
},
instanceMethods: {

View File

@ -115,7 +115,32 @@ const Document = sequelize.define(
},
classMethods: {
associate: models => {
Document.belongsTo(models.User);
Document.belongsTo(models.Collection, {
as: 'collection',
foreignKey: 'atlasId',
});
Document.belongsTo(models.User, {
as: 'createdBy',
foreignKey: 'createdById',
});
Document.belongsTo(models.User, {
as: 'updatedBy',
foreignKey: 'lastModifiedById',
});
Document.hasMany(models.Star, {
as: 'starred',
});
Document.addScope(
'defaultScope',
{
include: [
{ model: models.Collection, as: 'collection' },
{ model: models.User, as: 'createdBy' },
{ model: models.User, as: 'updatedBy' },
],
},
{ override: true }
);
},
findById: async id => {
if (isUUID(id)) {

View File

@ -1,8 +1,9 @@
// @flow
import _ from 'lodash';
import { Document } from '../models';
import { Collection } from '../models';
import presentDocument from './document';
async function present(ctx, collection, includeRecentDocuments = false) {
async function present(ctx: Object, collection: Collection) {
ctx.cache.set(collection.id, collection);
const data = {
@ -13,31 +14,21 @@ async function present(ctx, collection, includeRecentDocuments = false) {
type: collection.type,
createdAt: collection.createdAt,
updatedAt: collection.updatedAt,
recentDocuments: undefined,
documents: undefined,
};
if (collection.type === 'atlas')
if (collection.type === 'atlas') {
data.documents = await collection.getDocumentsStructure();
}
if (includeRecentDocuments) {
const documents = await Document.findAll({
where: {
atlasId: collection.id,
},
limit: 10,
order: [['updatedAt', 'DESC']],
});
const recentDocuments = [];
await Promise.all(
documents.map(async document => {
recentDocuments.push(
await presentDocument(ctx, document, {
includeCollaborators: true,
})
);
})
if (collection.documents) {
data.recentDocuments = await Promise.all(
collection.documents.map(
async document =>
await presentDocument(ctx, document, { includeCollaborators: true })
)
);
data.recentDocuments = _.orderBy(recentDocuments, ['updatedAt'], ['desc']);
}
return data;

View File

@ -1,17 +1,16 @@
import { Collection, Star, User, View } from '../models';
// @flow
import _ from 'lodash';
import { User, Document, View } from '../models';
import presentUser from './user';
import presentCollection from './collection';
async function present(ctx, document, options) {
async function present(ctx: Object, document: Document, options: Object = {}) {
options = {
includeCollection: true,
includeCollaborators: true,
includeViews: true,
includeViews: false,
...options,
};
ctx.cache.set(document.id, document);
const userId = ctx.state.user.id;
const data = {
id: document.id,
url: document.getUrl(),
@ -21,16 +20,19 @@ async function present(ctx, document, options) {
html: document.html,
preview: document.preview,
createdAt: document.createdAt,
createdBy: undefined,
createdBy: presentUser(ctx, document.createdBy),
updatedAt: document.updatedAt,
updatedBy: undefined,
updatedBy: presentUser(ctx, document.updatedBy),
team: document.teamId,
collaborators: [],
starred: !!document.starred,
collection: undefined,
views: undefined,
};
data.starred = !!await Star.findOne({
where: { documentId: document.id, userId },
});
if (document.private) {
data.collection = await presentCollection(ctx, document.collection);
}
if (options.includeViews) {
data.views = await View.sum('count', {
@ -38,42 +40,15 @@ async function present(ctx, document, options) {
});
}
if (options.includeCollection) {
data.collection = await ctx.cache.get(document.atlasId, async () => {
const collection =
options.collection ||
(await Collection.findOne({
where: {
id: document.atlasId,
},
}));
return presentCollection(ctx, collection);
});
}
if (options.includeCollaborators) {
// This could be further optimized by using ctx.cache
data.collaborators = await User.findAll({
where: {
id: {
$in: document.collaboratorIds || [],
},
id: { $in: _.takeRight(document.collaboratorIds, 10) || [] },
},
}).map(user => presentUser(ctx, user));
}
const createdBy = await ctx.cache.get(
document.createdById,
async () => await User.findById(document.createdById)
);
data.createdBy = await presentUser(ctx, createdBy);
const updatedBy = await ctx.cache.get(
document.lastModifiedById,
async () => await User.findById(document.lastModifiedById)
);
data.updatedBy = await presentUser(ctx, updatedBy);
return data;
}

View File

@ -1,4 +1,7 @@
function present(ctx, team) {
// @flow
import { Team } from '../models';
function present(ctx: Object, team: Team) {
ctx.cache.set(team.id, team);
return {