mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 11:05:54 +01:00 
			
		
		
		
	performance improvements
store parsed category description removed mongo _key from returns dont get category teaser for parent
This commit is contained in:
		| @@ -53,17 +53,11 @@ module.exports = function(Categories) { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (category.description) { | 		if (category.description) { | ||||||
| 			plugins.fireHook('filter:parse.raw', category.description, function(err, parsedDescription) { | 			category.description = validator.escape(category.description); | ||||||
| 				if (err) { | 			category.descriptionParsed = category.descriptionParsed || category.description; | ||||||
| 					return callback(err); |  | ||||||
| 				} |  | ||||||
| 				category.descriptionParsed = parsedDescription; |  | ||||||
| 				category.description = validator.escape(category.description); |  | ||||||
| 				callback(null, category); |  | ||||||
| 			}); |  | ||||||
| 		} else { |  | ||||||
| 			callback(null, category); |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		callback(null, category); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Categories.getCategoryField = function(cid, field, callback) { | 	Categories.getCategoryField = function(cid, field, callback) { | ||||||
|   | |||||||
| @@ -3,14 +3,13 @@ | |||||||
|  |  | ||||||
| var async = require('async'), | var async = require('async'), | ||||||
| 	winston = require('winston'), | 	winston = require('winston'), | ||||||
|  | 	validator = require('validator'), | ||||||
| 	_ = require('underscore'), | 	_ = require('underscore'), | ||||||
|  |  | ||||||
| 	meta = require('../meta'), |  | ||||||
| 	db = require('../database'), | 	db = require('../database'), | ||||||
| 	posts = require('../posts'), | 	posts = require('../posts'), | ||||||
| 	topics = require('../topics'), | 	topics = require('../topics'), | ||||||
| 	privileges = require('../privileges'), | 	privileges = require('../privileges'); | ||||||
| 	plugins = require('../plugins'); |  | ||||||
|  |  | ||||||
| module.exports = function(Categories) { | module.exports = function(Categories) { | ||||||
| 	Categories.getRecentReplies = function(cid, uid, count, callback) { | 	Categories.getRecentReplies = function(cid, uid, count, callback) { | ||||||
| @@ -38,25 +37,21 @@ module.exports = function(Categories) { | |||||||
|  |  | ||||||
| 		async.waterfall([ | 		async.waterfall([ | ||||||
| 			function(next) { | 			function(next) { | ||||||
| 				async.map(categoryData, getRecentTopicPids, next); | 				async.map(categoryData, getRecentTopicTids, next); | ||||||
| 			}, | 			}, | ||||||
| 			function(results, next) { | 			function(results, next) { | ||||||
| 				var pids = _.flatten(results); | 				var tids = _.flatten(results); | ||||||
|  |  | ||||||
| 				pids = pids.filter(function(pid, index, array) { | 				tids = tids.filter(function(tid, index, array) { | ||||||
| 					return !!pid && array.indexOf(pid) === index; | 					return !!tid && array.indexOf(tid) === index; | ||||||
| 				}); | 				}); | ||||||
| 				privileges.posts.filter('read', pids, uid, next); | 				privileges.topics.filterTids('read', tids, uid, next); | ||||||
| 			}, | 			}, | ||||||
| 			function(pids, next) { | 			function(tids, next) { | ||||||
| 				if (meta.config.teaserPost === 'first') { | 				getTopics(tids, next); | ||||||
| 					getMainPosts(pids, uid, next); |  | ||||||
| 				} else { |  | ||||||
| 					posts.getPostSummaryByPids(pids, uid, {stripTags: true}, next); |  | ||||||
| 				} |  | ||||||
| 			}, | 			}, | ||||||
| 			function(posts, next) { | 			function(topics, next) { | ||||||
| 				assignPostsToCategories(categoryData, posts); | 				assignTopicsToCategories(categoryData, topics); | ||||||
|  |  | ||||||
| 				bubbleUpChildrenPosts(categoryData); | 				bubbleUpChildrenPosts(categoryData); | ||||||
|  |  | ||||||
| @@ -65,29 +60,86 @@ module.exports = function(Categories) { | |||||||
| 		], callback); | 		], callback); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	function getMainPosts(pids, uid, callback) { | 	function getRecentTopicTids(category, callback) { | ||||||
|  | 		var count = parseInt(category.numRecentReplies, 10); | ||||||
|  | 		if (!count) { | ||||||
|  | 			return callback(null, []); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (count === 1) { | ||||||
|  | 			async.waterfall([ | ||||||
|  | 				function (next) { | ||||||
|  | 					db.getSortedSetRevRange('cid:' + category.cid + ':pids', 0, 0, next); | ||||||
|  | 				}, | ||||||
|  | 				function (pid, next) { | ||||||
|  | 					posts.getPostField(pid, 'tid', next); | ||||||
|  | 				}, | ||||||
|  | 				function (tid, next) { | ||||||
|  | 					next(null, [tid]); | ||||||
|  | 				} | ||||||
|  | 			], callback); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		async.parallel({ | ||||||
|  | 			pinnedTids: function(next) { | ||||||
|  | 				db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, -1, '+inf', Date.now(), next); | ||||||
|  | 			}, | ||||||
|  | 			tids: function(next) { | ||||||
|  | 				db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, Math.max(1, count), Date.now(), 0, next); | ||||||
|  | 			} | ||||||
|  | 		}, function(err, results) { | ||||||
|  | 			if (err) { | ||||||
|  | 				return callback(err); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			results.tids = results.tids.concat(results.pinnedTids); | ||||||
|  |  | ||||||
|  | 			callback(null, results.tids); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function getTopics(tids, callback) { | ||||||
|  | 		var topicData; | ||||||
| 		async.waterfall([ | 		async.waterfall([ | ||||||
| 			function(next) { | 			function (next) { | ||||||
| 				var keys = pids.map(function(pid) { | 				topics.getTopicsFields(tids, ['tid', 'mainPid', 'slug', 'title', 'teaserPid', 'cid', 'postcount'], next); | ||||||
| 					return 'post:' + pid; |  | ||||||
| 				}); |  | ||||||
| 				db.getObjectsFields(keys, ['tid'], next); |  | ||||||
| 			}, | 			}, | ||||||
| 			function(posts, next) { | 			function (_topicData, next) { | ||||||
| 				var keys = posts.map(function(post) { | 				topicData = _topicData; | ||||||
| 					return 'topic:' + post.tid; | 				topicData.forEach(function(topic) { | ||||||
|  | 					topic.teaserPid = topic.teaserPid || topic.mainPid; | ||||||
| 				}); | 				}); | ||||||
| 				db.getObjectsFields(keys, ['mainPid'], next); |  | ||||||
|  | 				topics.getTeasers(topicData, next); | ||||||
| 			}, | 			}, | ||||||
| 			function(topics, next) { | 			function (teasers, next) { | ||||||
| 				var mainPids = topics.map(function(topic) { | 				teasers.forEach(function(teaser, index) { | ||||||
| 					return topic.mainPid; | 					if (teaser) { | ||||||
|  | 						teaser.cid = topicData[index].cid; | ||||||
|  | 						teaser.tid = teaser.uid = teaser.user.uid = undefined; | ||||||
|  | 						teaser.topic = { | ||||||
|  | 							slug: topicData[index].slug, | ||||||
|  | 							title: validator.escape(topicData[index].title) | ||||||
|  | 						}; | ||||||
|  | 					} | ||||||
| 				}); | 				}); | ||||||
| 				posts.getPostSummaryByPids(mainPids, uid, {stripTags: true}, next); | 				teasers = teasers.filter(Boolean); | ||||||
|  | 				next(null, teasers); | ||||||
| 			} | 			} | ||||||
| 		], callback); | 		], callback); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	function assignTopicsToCategories(categories, topics) { | ||||||
|  | 		categories.forEach(function(category) { | ||||||
|  | 			category.posts = topics.filter(function(topic) { | ||||||
|  | 				return topic.cid && parseInt(topic.cid, 10) === parseInt(category.cid, 10); | ||||||
|  | 			}).sort(function(a, b) { | ||||||
|  | 				return b.pid - a.pid; | ||||||
|  | 			}).slice(0, parseInt(category.numRecentReplies, 10)); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	function bubbleUpChildrenPosts(categoryData) { | 	function bubbleUpChildrenPosts(categoryData) { | ||||||
| 		categoryData.forEach(function(category) { | 		categoryData.forEach(function(category) { | ||||||
| 			if (category.posts.length) { | 			if (category.posts.length) { | ||||||
| @@ -97,7 +149,7 @@ module.exports = function(Categories) { | |||||||
| 			getPostsRecursive(category, posts); | 			getPostsRecursive(category, posts); | ||||||
|  |  | ||||||
| 			posts.sort(function(a, b) { | 			posts.sort(function(a, b) { | ||||||
| 				return b.timestamp - a.timestamp; | 				return b.pid - a.pid; | ||||||
| 			}); | 			}); | ||||||
| 			if (posts.length) { | 			if (posts.length) { | ||||||
| 				category.posts = [posts[0]]; | 				category.posts = [posts[0]]; | ||||||
| @@ -115,64 +167,6 @@ module.exports = function(Categories) { | |||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function assignPostsToCategories(categories, posts) { |  | ||||||
| 		categories.forEach(function(category) { |  | ||||||
| 			category.posts = posts.filter(function(post) { |  | ||||||
| 				return post.category && (parseInt(post.category.cid, 10) === parseInt(category.cid, 10) || |  | ||||||
| 					parseInt(post.category.parentCid, 10) === parseInt(category.cid, 10)); |  | ||||||
| 			}).sort(function(a, b) { |  | ||||||
| 				return b.timestamp - a.timestamp; |  | ||||||
| 			}).slice(0, parseInt(category.numRecentReplies, 10)); |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	function getRecentTopicPids(category, callback) { |  | ||||||
| 		var count = parseInt(category.numRecentReplies, 10); |  | ||||||
| 		if (!count) { |  | ||||||
| 			return callback(null, []); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		db.getSortedSetRevRange('cid:' + category.cid + ':pids', 0, 0, function(err, pids) { |  | ||||||
| 			if (err || !Array.isArray(pids) || !pids.length) { |  | ||||||
| 				return callback(err, []); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if (count === 1) { |  | ||||||
| 				return callback(null, pids); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			async.parallel({ |  | ||||||
| 				pinnedTids: function(next) { |  | ||||||
| 					db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, -1, '+inf', Date.now(), next); |  | ||||||
| 				}, |  | ||||||
| 				tids: function(next) { |  | ||||||
| 					db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, Math.max(0, count), Date.now(), 0, next); |  | ||||||
| 				} |  | ||||||
| 			}, function(err, results) { |  | ||||||
| 				if (err) { |  | ||||||
| 					return callback(err); |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				results.tids = results.tids.concat(results.pinnedTids); |  | ||||||
|  |  | ||||||
| 				async.map(results.tids, topics.getLatestUndeletedPid, function(err, topicPids) { |  | ||||||
| 					if (err) { |  | ||||||
| 						return callback(err); |  | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 					pids = pids.concat(topicPids).filter(function(pid, index, array) { |  | ||||||
| 						return !!pid && array.indexOf(pid) === index; |  | ||||||
| 					}).sort(function(a, b) { |  | ||||||
| 						return b - a; |  | ||||||
| 					}).slice(0, count); |  | ||||||
|  |  | ||||||
| 					callback(null, pids); |  | ||||||
| 				}); |  | ||||||
| 			}); |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	Categories.moveRecentReplies = function(tid, oldCid, cid) { | 	Categories.moveRecentReplies = function(tid, oldCid, cid) { | ||||||
| 		updatePostCount(tid, oldCid, cid); | 		updatePostCount(tid, oldCid, cid); | ||||||
| 		topics.getPids(tid, function(err, pids) { | 		topics.getPids(tid, function(err, pids) { | ||||||
|   | |||||||
| @@ -68,6 +68,8 @@ module.exports = function(Categories) { | |||||||
|  |  | ||||||
| 			if (key === 'order') { | 			if (key === 'order') { | ||||||
| 				updateOrder(cid, value, callback); | 				updateOrder(cid, value, callback); | ||||||
|  | 			} else if (key === 'description') { | ||||||
|  | 				parseDescription(cid, value, callback); | ||||||
| 			} else { | 			} else { | ||||||
| 				callback(); | 				callback(); | ||||||
| 			} | 			} | ||||||
| @@ -119,4 +121,13 @@ module.exports = function(Categories) { | |||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	function parseDescription(cid, description, callback) { | ||||||
|  | 		plugins.fireHook('filter:parse.raw', description, function(err, parsedDescription) { | ||||||
|  | 			if (err) { | ||||||
|  | 				return callback(err); | ||||||
|  | 			} | ||||||
|  | 			Categories.setCategoryField(cid, 'descriptionParsed', parsedDescription, callback); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -69,7 +69,7 @@ categoriesController.list = function(req, res, next) { | |||||||
| 			if (category && Array.isArray(category.posts) && category.posts.length) { | 			if (category && Array.isArray(category.posts) && category.posts.length) { | ||||||
| 				category.teaser = { | 				category.teaser = { | ||||||
| 					url: nconf.get('relative_path') + '/topic/' + category.posts[0].topic.slug + '/' + category.posts[0].index, | 					url: nconf.get('relative_path') + '/topic/' + category.posts[0].topic.slug + '/' + category.posts[0].index, | ||||||
| 					timestampISO: category.posts[0].relativeTime | 					timestampISO: category.posts[0].timestamp | ||||||
| 				}; | 				}; | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| @@ -203,8 +203,11 @@ categoriesController.get = function(req, res, callback) { | |||||||
| 			}); | 			}); | ||||||
| 		}, | 		}, | ||||||
| 		function(categoryData, next) { | 		function(categoryData, next) { | ||||||
|  | 			if (!categoryData.children.length) { | ||||||
|  | 				return next(null, categoryData); | ||||||
|  | 			} | ||||||
| 			var allCategories = []; | 			var allCategories = []; | ||||||
| 			categories.flattenCategories(allCategories, [categoryData]); | 			categories.flattenCategories(allCategories, categoryData.children); | ||||||
| 			categories.getRecentTopicReplies(allCategories, req.uid, function(err) { | 			categories.getRecentTopicReplies(allCategories, req.uid, function(err) { | ||||||
| 				next(err, categoryData); | 				next(err, categoryData); | ||||||
| 			}); | 			}); | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ helpers.toMap = function(data) { | |||||||
| 	var map = {}; | 	var map = {}; | ||||||
| 	for (var i = 0; i<data.length; ++i) { | 	for (var i = 0; i<data.length; ++i) { | ||||||
| 		map[data[i]._key] = data[i]; | 		map[data[i]._key] = data[i]; | ||||||
|  | 		data[i]._key = undefined; | ||||||
| 	} | 	} | ||||||
| 	return map; | 	return map; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -125,7 +125,7 @@ module.exports = function(db, module) { | |||||||
| 		if (withScores) { | 		if (withScores) { | ||||||
| 			fields.score = 1; | 			fields.score = 1; | ||||||
| 		} | 		} | ||||||
| 		db.collection('objects').find({_key:key}, {fields: fields}) | 		db.collection('objects').find({_key: key}, {fields: fields}) | ||||||
| 			.limit(stop - start + 1) | 			.limit(stop - start + 1) | ||||||
| 			.skip(start) | 			.skip(start) | ||||||
| 			.sort({score: sort}) | 			.sort({score: sort}) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user