mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: allow passing min,max to sortedSetsCardSum
to get rid of multiple db calls in profile page
This commit is contained in:
@@ -180,8 +180,8 @@ async function getCounts(userData, callerUID) {
|
|||||||
const cids = await categories.getCidsByPrivilege('categories:cid', callerUID, 'topics:read');
|
const cids = await categories.getCidsByPrivilege('categories:cid', callerUID, 'topics:read');
|
||||||
const promises = {
|
const promises = {
|
||||||
posts: db.sortedSetsCardSum(cids.map(c => `cid:${c}:uid:${uid}:pids`)),
|
posts: db.sortedSetsCardSum(cids.map(c => `cid:${c}:uid:${uid}:pids`)),
|
||||||
best: Promise.all(cids.map(async c => db.sortedSetCount(`cid:${c}:uid:${uid}:pids:votes`, 1, '+inf'))),
|
best: db.sortedSetsCardSum(cids.map(c => `cid:${c}:uid:${uid}:pids:votes`), 1, '+inf'),
|
||||||
controversial: Promise.all(cids.map(async c => db.sortedSetCount(`cid:${c}:uid:${uid}:pids:votes`, '-inf', -1))),
|
controversial: db.sortedSetsCardSum(cids.map(c => `cid:${c}:uid:${uid}:pids:votes`), '-inf', -1),
|
||||||
topics: db.sortedSetsCardSum(cids.map(c => `cid:${c}:uid:${uid}:tids`)),
|
topics: db.sortedSetsCardSum(cids.map(c => `cid:${c}:uid:${uid}:tids`)),
|
||||||
};
|
};
|
||||||
if (userData.isAdmin || userData.isSelf) {
|
if (userData.isAdmin || userData.isSelf) {
|
||||||
@@ -196,8 +196,6 @@ async function getCounts(userData, callerUID) {
|
|||||||
promises.blocks = user.getUserField(userData.uid, 'blocksCount');
|
promises.blocks = user.getUserField(userData.uid, 'blocksCount');
|
||||||
}
|
}
|
||||||
const counts = await utils.promiseParallel(promises);
|
const counts = await utils.promiseParallel(promises);
|
||||||
counts.best = counts.best.reduce((sum, count) => sum + count, 0);
|
|
||||||
counts.controversial = counts.controversial.reduce((sum, count) => sum + count, 0);
|
|
||||||
counts.categoriesWatched = counts.categoriesWatched && counts.categoriesWatched.length;
|
counts.categoriesWatched = counts.categoriesWatched && counts.categoriesWatched.length;
|
||||||
counts.groups = userData.groups.length;
|
counts.groups = userData.groups.length;
|
||||||
counts.following = userData.followingCount;
|
counts.following = userData.followingCount;
|
||||||
|
|||||||
@@ -157,33 +157,39 @@ module.exports = function (module) {
|
|||||||
query.score.$lte = max;
|
query.score.$lte = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
const count = await module.client.collection('objects').countDocuments(query);
|
return await module.client.collection('objects').countDocuments(query);
|
||||||
return count || 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.sortedSetCard = async function (key) {
|
module.sortedSetCard = async function (key) {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const count = await module.client.collection('objects').countDocuments({ _key: key });
|
return await module.client.collection('objects').countDocuments({ _key: key });
|
||||||
return parseInt(count, 10) || 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.sortedSetsCard = async function (keys) {
|
module.sortedSetsCard = async function (keys) {
|
||||||
if (!Array.isArray(keys) || !keys.length) {
|
if (!Array.isArray(keys) || !keys.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const promises = keys.map(k => module.sortedSetCard(k));
|
return await Promise.all(keys.map(module.sortedSetCard));
|
||||||
return await Promise.all(promises);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.sortedSetsCardSum = async function (keys) {
|
module.sortedSetsCardSum = async function (keys, min = '-inf', max = '+inf') {
|
||||||
if (!keys || (Array.isArray(keys) && !keys.length)) {
|
const isArray = Array.isArray(keys);
|
||||||
|
if (!keys || (isArray && !keys.length)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const count = await module.client.collection('objects').countDocuments({ _key: Array.isArray(keys) ? { $in: keys } : keys });
|
const query = { _key: isArray ? { $in: keys } : keys };
|
||||||
return parseInt(count, 10) || 0;
|
if (min !== '-inf') {
|
||||||
|
query.score = { $gte: min };
|
||||||
|
}
|
||||||
|
if (max !== '+inf') {
|
||||||
|
query.score = query.score || {};
|
||||||
|
query.score.$lte = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await module.client.collection('objects').countDocuments(query);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.sortedSetRank = async function (key, value) {
|
module.sortedSetRank = async function (key, value) {
|
||||||
|
|||||||
@@ -221,16 +221,42 @@ SELECT o."_key" k,
|
|||||||
return keys.map(k => parseInt((res.rows.find(r => r.k === k) || { c: 0 }).c, 10));
|
return keys.map(k => parseInt((res.rows.find(r => r.k === k) || { c: 0 }).c, 10));
|
||||||
};
|
};
|
||||||
|
|
||||||
module.sortedSetsCardSum = async function (keys) {
|
module.sortedSetsCardSum = async function (keys, min = '-inf', max = '+inf') {
|
||||||
if (!keys || (Array.isArray(keys) && !keys.length)) {
|
if (!keys || (Array.isArray(keys) && !keys.length)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!Array.isArray(keys)) {
|
if (!Array.isArray(keys)) {
|
||||||
keys = [keys];
|
keys = [keys];
|
||||||
}
|
}
|
||||||
const counts = await module.sortedSetsCard(keys);
|
let counts = [];
|
||||||
const sum = counts.reduce((acc, val) => acc + val, 0);
|
if (min !== '-inf' || max !== '+inf') {
|
||||||
return sum;
|
if (min === '-inf') {
|
||||||
|
min = null;
|
||||||
|
}
|
||||||
|
if (max === '+inf') {
|
||||||
|
max = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await module.pool.query({
|
||||||
|
name: 'sortedSetsCardSum',
|
||||||
|
text: `
|
||||||
|
SELECT o."_key" k,
|
||||||
|
COUNT(*) c
|
||||||
|
FROM "legacy_object_live" o
|
||||||
|
INNER JOIN "legacy_zset" z
|
||||||
|
ON o."_key" = z."_key"
|
||||||
|
AND o."type" = z."type"
|
||||||
|
WHERE o."_key" = ANY($1::TEXT[])
|
||||||
|
AND (z."score" >= $2::NUMERIC OR $2::NUMERIC IS NULL)
|
||||||
|
AND (z."score" <= $3::NUMERIC OR $3::NUMERIC IS NULL)
|
||||||
|
GROUP BY o."_key"`,
|
||||||
|
values: [keys, min, max],
|
||||||
|
});
|
||||||
|
counts = keys.map(k => parseInt((res.rows.find(r => r.k === k) || { c: 0 }).c, 10));
|
||||||
|
} else {
|
||||||
|
counts = await module.sortedSetsCard(keys);
|
||||||
|
}
|
||||||
|
return counts.reduce((acc, val) => acc + val, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.sortedSetRank = async function (key, value) {
|
module.sortedSetRank = async function (key, value) {
|
||||||
|
|||||||
@@ -116,16 +116,21 @@ module.exports = function (module) {
|
|||||||
return await helpers.execBatch(batch);
|
return await helpers.execBatch(batch);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.sortedSetsCardSum = async function (keys) {
|
module.sortedSetsCardSum = async function (keys, min = '-inf', max = '+inf') {
|
||||||
if (!keys || (Array.isArray(keys) && !keys.length)) {
|
if (!keys || (Array.isArray(keys) && !keys.length)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!Array.isArray(keys)) {
|
if (!Array.isArray(keys)) {
|
||||||
keys = [keys];
|
keys = [keys];
|
||||||
}
|
}
|
||||||
const counts = await module.sortedSetsCard(keys);
|
const batch = module.client.batch();
|
||||||
const sum = counts.reduce((acc, val) => acc + val, 0);
|
if (min !== '-inf' || max !== '+inf') {
|
||||||
return sum;
|
keys.forEach(k => batch.zcount(String(k), min, max));
|
||||||
|
} else {
|
||||||
|
keys.forEach(k => batch.zcard(String(k)));
|
||||||
|
}
|
||||||
|
const counts = await helpers.execBatch(batch);
|
||||||
|
return counts.reduce((acc, val) => acc + val, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.sortedSetRank = async function (key, value) {
|
module.sortedSetRank = async function (key, value) {
|
||||||
|
|||||||
@@ -1,29 +1,17 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
const async = require('async');
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const db = require('../mocks/databasemock');
|
const db = require('../mocks/databasemock');
|
||||||
|
|
||||||
describe('Sorted Set methods', () => {
|
describe('Sorted Set methods', () => {
|
||||||
before((done) => {
|
before(async () => {
|
||||||
async.parallel([
|
await Promise.all([
|
||||||
function (next) {
|
db.sortedSetAdd('sortedSetTest1', [1.1, 1.2, 1.3], ['value1', 'value2', 'value3']),
|
||||||
db.sortedSetAdd('sortedSetTest1', [1.1, 1.2, 1.3], ['value1', 'value2', 'value3'], next);
|
db.sortedSetAdd('sortedSetTest2', [1, 4], ['value1', 'value4']),
|
||||||
},
|
db.sortedSetAdd('sortedSetTest3', [2, 4], ['value2', 'value4']),
|
||||||
function (next) {
|
db.sortedSetAdd('sortedSetTest4', [1, 1, 2, 3, 5], ['b', 'a', 'd', 'e', 'c']),
|
||||||
db.sortedSetAdd('sortedSetTest2', [1, 4], ['value1', 'value4'], next);
|
db.sortedSetAdd('sortedSetLex', [0, 0, 0, 0], ['a', 'b', 'c', 'd']),
|
||||||
},
|
]);
|
||||||
function (next) {
|
|
||||||
db.sortedSetAdd('sortedSetTest3', [2, 4], ['value2', 'value4'], next);
|
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
db.sortedSetAdd('sortedSetTest4', [1, 1, 2, 3, 5], ['b', 'a', 'd', 'e', 'c'], next);
|
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
db.sortedSetAdd('sortedSetLex', [0, 0, 0, 0], ['a', 'b', 'c', 'd'], next);
|
|
||||||
},
|
|
||||||
], done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('sortedSetScan', () => {
|
describe('sortedSetScan', () => {
|
||||||
@@ -617,6 +605,23 @@ describe('Sorted Set methods', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should work with min/max', async () => {
|
||||||
|
let count = await db.sortedSetsCardSum([
|
||||||
|
'sortedSetTest1', 'sortedSetTest2', 'sortedSetTest3',
|
||||||
|
], '-inf', 2);
|
||||||
|
assert.strictEqual(count, 5);
|
||||||
|
|
||||||
|
count = await db.sortedSetsCardSum([
|
||||||
|
'sortedSetTest1', 'sortedSetTest2', 'sortedSetTest3',
|
||||||
|
], 2, '+inf');
|
||||||
|
assert.strictEqual(count, 3);
|
||||||
|
|
||||||
|
count = await db.sortedSetsCardSum([
|
||||||
|
'sortedSetTest1', 'sortedSetTest2', 'sortedSetTest3',
|
||||||
|
], '-inf', '+inf');
|
||||||
|
assert.strictEqual(count, 7);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('sortedSetRank()', () => {
|
describe('sortedSetRank()', () => {
|
||||||
@@ -1225,11 +1230,11 @@ describe('Sorted Set methods', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('sortedSetsRemove()', () => {
|
describe('sortedSetsRemove()', () => {
|
||||||
before((done) => {
|
before(async () => {
|
||||||
async.parallel([
|
await Promise.all([
|
||||||
async.apply(db.sortedSetAdd, 'sorted4', [1, 2], ['value1', 'value2']),
|
db.sortedSetAdd('sorted4', [1, 2], ['value1', 'value2']),
|
||||||
async.apply(db.sortedSetAdd, 'sorted5', [1, 2], ['value1', 'value3']),
|
db.sortedSetAdd('sorted5', [1, 2], ['value1', 'value3']),
|
||||||
], done);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove element from multiple sorted sets', (done) => {
|
it('should remove element from multiple sorted sets', (done) => {
|
||||||
@@ -1278,15 +1283,11 @@ describe('Sorted Set methods', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('getSortedSetIntersect', () => {
|
describe('getSortedSetIntersect', () => {
|
||||||
before((done) => {
|
before(async () => {
|
||||||
async.parallel([
|
await Promise.all([
|
||||||
function (next) {
|
db.sortedSetAdd('interSet1', [1, 2, 3], ['value1', 'value2', 'value3']),
|
||||||
db.sortedSetAdd('interSet1', [1, 2, 3], ['value1', 'value2', 'value3'], next);
|
db.sortedSetAdd('interSet2', [4, 5, 6], ['value2', 'value3', 'value5']),
|
||||||
},
|
]);
|
||||||
function (next) {
|
|
||||||
db.sortedSetAdd('interSet2', [4, 5, 6], ['value2', 'value3', 'value5'], next);
|
|
||||||
},
|
|
||||||
], done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the intersection of two sets', (done) => {
|
it('should return the intersection of two sets', (done) => {
|
||||||
@@ -1446,21 +1447,13 @@ describe('Sorted Set methods', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('sortedSetIntersectCard', () => {
|
describe('sortedSetIntersectCard', () => {
|
||||||
before((done) => {
|
before(async () => {
|
||||||
async.parallel([
|
await Promise.all([
|
||||||
function (next) {
|
db.sortedSetAdd('interCard1', [0, 0, 0], ['value1', 'value2', 'value3']),
|
||||||
db.sortedSetAdd('interCard1', [0, 0, 0], ['value1', 'value2', 'value3'], next);
|
db.sortedSetAdd('interCard2', [0, 0, 0], ['value2', 'value3', 'value4']),
|
||||||
},
|
db.sortedSetAdd('interCard3', [0, 0, 0], ['value3', 'value4', 'value5']),
|
||||||
function (next) {
|
db.sortedSetAdd('interCard4', [0, 0, 0], ['value4', 'value5', 'value6']),
|
||||||
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', (done) => {
|
it('should return # of elements in intersection', (done) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user