diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index fbb727d9c9..292f8574ee 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -637,6 +637,24 @@ module.exports = function(db, module) { }; + module.sortedSetIntersectCard = function(keys, callback) { + if (!Array.isArray(keys) || !keys.length) { + return callback(null, 0); + } + + var pipeline = [ + { $match: { _key: {$in: keys}} }, + { $group: { _id: {value: '$value'}, count: {$sum: 1}} }, + { $match: { count: keys.length} }, + { $group: { _id: null, count: { $sum: 1 } } }, + { $project: { _id: 0, count: '$count' } } + ]; + + db.collection('objects').aggregate(pipeline, function(err, data) { + callback(err, Array.isArray(data) && data.length ? data[0].count : 0); + }); + }; + module.getSortedSetIntersect = function(params, callback) { params.sort = 1; getSortedSetRevIntersect(params, callback); diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index f39189cf0f..b906e10575 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -93,7 +93,7 @@ module.exports = function(redisClient, module) { function sortedSetRange(method, key, start, stop, withScores, callback) { if (Array.isArray(key)) { - return sortedSetUnion(method, key, start, stop, withScores, callback); + return sortedSetUnion({method: method, sets: key, start: start, stop: stop, withScores: withScores}, callback); } var params = [key, start, stop]; @@ -265,7 +265,7 @@ module.exports = function(redisClient, module) { var rangeParams = [tempSetName, params.start, params.stop]; if (params.withScores) { - params.push('WITHSCORES'); + rangeParams.push('WITHSCORES'); } var multi = redisClient.multi(); @@ -302,6 +302,27 @@ module.exports = function(redisClient, module) { redisClient.zrangebylex([key, min, max, 'LIMIT', start, count], callback); }; + module.sortedSetIntersectCard = function(keys, callback) { + if (!Array.isArray(keys) || !keys.length) { + return callback(null, 0); + } + var tempSetName = 'temp_' + Date.now(); + + var interParams = [tempSetName, keys.length].concat(keys); + + var multi = redisClient.multi(); + multi.zinterstore(interParams); + multi.zcard(tempSetName); + multi.del(tempSetName); + multi.exec(function(err, results) { + if (err) { + return callback(err); + } + + callback(null, results[1] || 0); + }); + }; + module.getSortedSetIntersect = function(params, callback) { params.method = 'zrange'; getSortedSetRevIntersect(params, callback); @@ -312,7 +333,7 @@ module.exports = function(redisClient, module) { getSortedSetRevIntersect(params, callback); }; - function getSortedSetRevIntersect (params, callback) { + function getSortedSetRevIntersect(params, callback) { var sets = params.sets; var start = params.hasOwnProperty('start') ? params.start : 0; var stop = params.hasOwnProperty('stop') ? params.stop : -1; diff --git a/src/topics.js b/src/topics.js index 7d9938987a..3248d8f567 100644 --- a/src/topics.js +++ b/src/topics.js @@ -346,7 +346,7 @@ var social = require('./social'); }; Topics.getTopicBookmarks = function( tid, callback ){ - db.getSortedSetRangeWithScores(['tid:' + tid + ':bookmarks'], 0, -1, callback ); + db.getSortedSetRangeWithScores(['tid:' + tid + ':bookmarks'], 0, -1, callback); }; Topics.updateTopicBookmarks = function(tid, pids, callback) { diff --git a/tests/database/sorted.js b/tests/database/sorted.js index 91da2c657c..293eef8e43 100644 --- a/tests/database/sorted.js +++ b/tests/database/sorted.js @@ -659,6 +659,41 @@ describe('Sorted Set methods', function() { }); + describe('sortedSetIntersectCard', function() { + before(function(done) { + async.parallel([ + function(next) { + db.sortedSetAdd('interCard1', [0, 0, 0], ['value1', 'value2', 'value3'], next); + }, + function(next) { + db.sortedSetAdd('interCard2', [0, 0, 0], ['value2', 'value3', 'value4'], next); + }, + function(next) { + db.sortedSetAdd('interCard3', [0, 0, 0], ['value3', 'value4', 'value5'], next); + }, + function(next) { + db.sortedSetAdd('interCard4', [0, 0, 0], ['value4', 'value5', 'value6'], next); + } + ], done); + }); + + it('should return # of elements in intersection', function(done) { + db.sortedSetIntersectCard(['interCard1', 'interCard2', 'interCard3'], function(err, count) { + assert.ifError(err); + assert.strictEqual(count, 1); + done(); + }); + }); + + it('should return 0 if intersection is empty', function(done) { + db.sortedSetIntersectCard(['interCard1', 'interCard4'], function(err, count) { + assert.ifError(err); + assert.strictEqual(count, 0); + done(); + }); + }); + }); + after(function(done) { db.flushdb(done);