mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-11-03 20:45:58 +01:00 
			
		
		
		
	optimized getTopicsByTids, single db call to get topicData, added cache for privilege/category/user data
This commit is contained in:
		@@ -48,8 +48,8 @@
 | 
			
		||||
						todo: fix this nesting if issue#1065 is a win
 | 
			
		||||
						todo: add a check for config.allowTopicsThumbnail if issue#1066 is a win
 | 
			
		||||
					-->
 | 
			
		||||
					<a href="../../user/{topics.userslug}" class="pull-left">
 | 
			
		||||
						<img src="<!-- IF topics.thumb -->{topics.thumb}<!-- ELSE -->{topics.picture}<!-- ENDIF topics.thumb -->" class="img-rounded user-img" title="{topics.username}"/>
 | 
			
		||||
					<a href="../../user/{topics.user.userslug}" class="pull-left">
 | 
			
		||||
						<img src="<!-- IF topics.thumb -->{topics.thumb}<!-- ELSE -->{topics.user.picture}<!-- ENDIF topics.thumb -->" class="img-rounded user-img" title="{topics.user.username}"/>
 | 
			
		||||
					</a>
 | 
			
		||||
 | 
			
		||||
					<h3>
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,8 @@
 | 
			
		||||
		<!-- BEGIN topics -->
 | 
			
		||||
		<li class="category-item <!-- IF topics.deleted --> deleted<!-- ENDIF topics.deleted --><!-- IF topics.unread --> unread<!-- ENDIF topics.unread -->">
 | 
			
		||||
			<div class="col-md-12 col-xs-12 panel panel-default topic-row">
 | 
			
		||||
				<a href="{relative_path}/user/{topics.userslug}" class="pull-left">
 | 
			
		||||
					<img class="img-rounded user-img" src="{topics.picture}" title="{topics.username}" />
 | 
			
		||||
				<a href="{relative_path}/user/{topics.user.userslug}" class="pull-left">
 | 
			
		||||
					<img class="img-rounded user-img" src="{topics.user.picture}" title="{topics.user.username}" />
 | 
			
		||||
				</a>
 | 
			
		||||
 | 
			
		||||
				<h3>
 | 
			
		||||
 
 | 
			
		||||
@@ -27,8 +27,8 @@
 | 
			
		||||
		<!-- BEGIN topics -->
 | 
			
		||||
		<li class="category-item <!-- IF topics.deleted --> deleted<!-- ENDIF topics.deleted --><!-- IF topics.unread --> unread<!-- ENDIF topics.unread -->">
 | 
			
		||||
			<div class="col-md-12 col-xs-12 panel panel-default topic-row">
 | 
			
		||||
				<a href="{relative_path}/user/{topics.userslug}" class="pull-left">
 | 
			
		||||
					<img class="img-rounded user-img" src="{topics.picture}" title="{topics.username}" />
 | 
			
		||||
				<a href="{relative_path}/user/{topics.user.userslug}" class="pull-left">
 | 
			
		||||
					<img class="img-rounded user-img" src="{topics.user.picture}" title="{topics.user.username}" />
 | 
			
		||||
				</a>
 | 
			
		||||
 | 
			
		||||
				<h3>
 | 
			
		||||
 
 | 
			
		||||
@@ -21,8 +21,8 @@
 | 
			
		||||
			<!-- BEGIN topics -->
 | 
			
		||||
			<li class="category-item<!-- IF topics.deleted --> deleted<!-- ENDIF topics.deleted -->" data-tid="{topics.tid}">
 | 
			
		||||
				<div class="col-md-12 col-xs-12 panel panel-default topic-row">
 | 
			
		||||
					<a href="{relative_path}/user/{topics.userslug}" class="pull-left">
 | 
			
		||||
						<img class="img-rounded user-img" src="{topics.picture}" title="{topics.username}" />
 | 
			
		||||
					<a href="{relative_path}/user/{topics.user.userslug}" class="pull-left">
 | 
			
		||||
						<img class="img-rounded user-img" src="{topics.user.picture}" title="{topics.user.username}" />
 | 
			
		||||
					</a>
 | 
			
		||||
					<h3>
 | 
			
		||||
						<a href="{relative_path}/topic/{topics.slug}">
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										107
									
								
								src/topics.js
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								src/topics.js
									
									
									
									
									
								
							@@ -323,17 +323,35 @@ var async = require('async'),
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Topics.getTopicData = function(tid, callback) {
 | 
			
		||||
		db.getObject('topic:' + tid, function(err, data) {
 | 
			
		||||
			if(err) {
 | 
			
		||||
				return callback(err, null);
 | 
			
		||||
		Topics.getTopicsData([tid], function(err, topics) {
 | 
			
		||||
			if (err) {
 | 
			
		||||
				return callback(err);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if(data) {
 | 
			
		||||
				data.title = validator.escape(data.title);
 | 
			
		||||
				data.relativeTime = utils.toISOString(data.timestamp);
 | 
			
		||||
			callback(null, topics ? topics[0] : null);
 | 
			
		||||
		});
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Topics.getTopicsData = function(tids, callback) {
 | 
			
		||||
		var keys = [];
 | 
			
		||||
 | 
			
		||||
		for (var i=0; i<tids.length; ++i) {
 | 
			
		||||
			keys.push('topic:' + tids[i]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			callback(null, data);
 | 
			
		||||
		db.getObjects(keys, function(err, topics) {
 | 
			
		||||
			if (err) {
 | 
			
		||||
				return callback(err);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for (var i=0; i<tids.length; ++i) {
 | 
			
		||||
				if(topics[i]) {
 | 
			
		||||
					topics[i].title = validator.escape(topics[i].title);
 | 
			
		||||
					topics[i].relativeTime = utils.toISOString(topics[i].timestamp);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			callback(null, topics);
 | 
			
		||||
		});
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
@@ -671,46 +689,53 @@ var async = require('async'),
 | 
			
		||||
			return callback(null, []);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		function getTopicInfo(topicData, callback) {
 | 
			
		||||
			async.parallel({
 | 
			
		||||
				hasread : function (next) {
 | 
			
		||||
					Topics.hasReadTopic(topicData.tid, uid, next);
 | 
			
		||||
				},
 | 
			
		||||
				teaser : function (next) {
 | 
			
		||||
					Topics.getTeaser(topicData.tid, next);
 | 
			
		||||
				},
 | 
			
		||||
				privileges : function (next) {
 | 
			
		||||
					categoryTools.privileges(topicData.cid, uid, next);
 | 
			
		||||
				},
 | 
			
		||||
				categoryData : function (next) {
 | 
			
		||||
					categories.getCategoryFields(topicData.cid, ['name', 'slug', 'icon'], next);
 | 
			
		||||
				}
 | 
			
		||||
			}, callback);
 | 
			
		||||
		}
 | 
			
		||||
		var categoryCache = {},
 | 
			
		||||
			privilegeCache = {},
 | 
			
		||||
			userCache = {};
 | 
			
		||||
 | 
			
		||||
		function loadTopicInfo(topicData, next) {
 | 
			
		||||
 | 
			
		||||
			function isTopicVisible(topicData, topicInfo) {
 | 
			
		||||
				var deleted = parseInt(topicData.deleted, 10) !== 0;
 | 
			
		||||
 | 
			
		||||
				return !deleted || (deleted && topicInfo.privileges.view_deleted) || parseInt(topicData.uid, 10) === parseInt(uid, 10);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		function loadTopic(tid, next) {
 | 
			
		||||
 | 
			
		||||
			Topics.getTopicDataWithUser(tid, function(err, topicData) {
 | 
			
		||||
			async.parallel({
 | 
			
		||||
				hasread: function(next) {
 | 
			
		||||
					Topics.hasReadTopic(topicData.tid, uid, next);
 | 
			
		||||
				},
 | 
			
		||||
				teaser: function(next) {
 | 
			
		||||
					Topics.getTeaser(topicData.tid, next);
 | 
			
		||||
				},
 | 
			
		||||
				privileges: function(next) {
 | 
			
		||||
					if (privilegeCache[topicData.cid]) {
 | 
			
		||||
						return next(null, privilegeCache[topicData.cid])
 | 
			
		||||
					}
 | 
			
		||||
					categoryTools.privileges(topicData.cid, uid, next);
 | 
			
		||||
				},
 | 
			
		||||
				categoryData: function(next) {
 | 
			
		||||
					if (categoryCache[topicData.cid]) {
 | 
			
		||||
						return next(null, categoryCache[topicData.cid]);
 | 
			
		||||
					}
 | 
			
		||||
					categories.getCategoryFields(topicData.cid, ['name', 'slug', 'icon'], next);
 | 
			
		||||
				},
 | 
			
		||||
				user: function(next) {
 | 
			
		||||
					if (userCache[topicData.uid]) {
 | 
			
		||||
						return next(null, userCache[topicData.uid]);
 | 
			
		||||
					}
 | 
			
		||||
					user.getUserFields(topicData.uid, ['username', 'userslug', 'picture'], next);
 | 
			
		||||
				}
 | 
			
		||||
			}, function(err, topicInfo) {
 | 
			
		||||
				if(err) {
 | 
			
		||||
					return next(err);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (!topicData) {
 | 
			
		||||
					return next();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				getTopicInfo(topicData, function(err, topicInfo) {
 | 
			
		||||
					if(err) {
 | 
			
		||||
						return next(err);
 | 
			
		||||
					}
 | 
			
		||||
				privilegeCache[topicData.cid] = topicInfo.privileges;
 | 
			
		||||
				categoryCache[topicData.cid] = topicInfo.categoryData;
 | 
			
		||||
				userCache[topicData.uid] = topicInfo.user;
 | 
			
		||||
 | 
			
		||||
				if (!isTopicVisible(topicData, topicInfo)) {
 | 
			
		||||
					topicData = null;
 | 
			
		||||
					return next();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
@@ -722,13 +747,18 @@ var async = require('async'),
 | 
			
		||||
 | 
			
		||||
				topicData.category = topicInfo.categoryData;
 | 
			
		||||
				topicData.teaser = topicInfo.teaser;
 | 
			
		||||
				topicData.user = topicInfo.user;
 | 
			
		||||
 | 
			
		||||
					next(null, topicData);
 | 
			
		||||
				});
 | 
			
		||||
				next();
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		async.map(tids, loadTopic, function(err, topics) {
 | 
			
		||||
		Topics.getTopicsData(tids, function(err, topics) {
 | 
			
		||||
			if (err) {
 | 
			
		||||
				return callback(err);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			async.eachSeries(topics, loadTopicInfo, function(err) {
 | 
			
		||||
				if(err) {
 | 
			
		||||
					return callback(err);
 | 
			
		||||
				}
 | 
			
		||||
@@ -739,6 +769,7 @@ var async = require('async'),
 | 
			
		||||
 | 
			
		||||
				callback(null, topics);
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Topics.getTopicWithPosts = function(tid, uid, start, end, callback) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user