perf: make a single round trip for set(s)Remove

use bulkWrite
This commit is contained in:
Barış Soner Uşaklı
2026-03-09 18:33:24 -04:00
parent 997efcd18b
commit bcbb7bc444
3 changed files with 33 additions and 42 deletions

View File

@@ -94,44 +94,31 @@ module.exports = function (module) {
};
module.setRemove = async function (key, value) {
if (!Array.isArray(value)) {
value = [value];
}
value = value.map(v => helpers.valueToString(v));
const coll = module.client.collection('objects');
await coll.updateMany({
_key: Array.isArray(key) ? { $in: key } : key,
}, {
$pullAll: { members: value },
});
await coll.deleteMany({
_key: Array.isArray(key) ? { $in: key } : key,
members: { $size: 0 },
});
await bulkSetRemove(key, value);
};
module.setsRemove = async function (keys, value) {
if (!Array.isArray(keys) || !keys.length) {
return;
}
value = helpers.valueToString(value);
const coll = module.client.collection('objects');
await coll.updateMany({
_key: { $in: keys },
}, {
$pull: { members: value },
});
await coll.deleteMany({
_key: { $in: keys },
members: { $size: 0 },
});
await bulkSetRemove(keys, value);
};
async function bulkSetRemove(key, values) {
const isKeyArray = Array.isArray(key);
if (!key || (isKeyArray && !key.length)) return;
const filterKey = isKeyArray ? { $in: key } : key;
const update = Array.isArray(values) ?
{ $pullAll: { members: values.map(helpers.valueToString) } } :
{ $pull: { members: helpers.valueToString(values) } };
await module.client.collection('objects').bulkWrite([
{ updateMany: { filter: { _key: filterKey }, update: update } },
{ deleteMany: { filter: { _key: filterKey, members: { $size: 0 } } } },
], { ordered: true });
}
module.isSetMember = async function (key, value) {
if (!key) {
return false;

View File

@@ -57,6 +57,9 @@ module.exports = function (module) {
};
module.setsRemove = async function (keys, value) {
if (!Array.isArray(keys) || !keys.length) {
return;
}
const batch = module.client.batch();
keys.forEach(k => batch.sRem(String(k), String(value)));
await helpers.execBatch(batch);

View File

@@ -278,20 +278,21 @@ describe('Set methods', () => {
});
describe('setsRemove()', () => {
before((done) => {
db.setsAdd(['set1', 'set2'], 'value', done);
it('should remove a element from multiple sets', async () => {
await db.setsAdd(['set1', 'set2'], 'value');
await db.setRemove(['set1', 'set2'], 'value');
const members = await db.isMemberOfSets(['set1', 'set2'], 'value');
assert.deepStrictEqual(members, [false, false]);
});
it('should remove a element from multiple sets', (done) => {
db.setsRemove(['set1', 'set2'], 'value', function (err) {
assert.equal(err, null);
assert.equal(arguments.length, 1);
db.isMemberOfSets(['set1', 'set2'], 'value', (err, members) => {
assert.equal(err, null);
assert.deepEqual(members, [false, false]);
done();
});
});
it('should remove the sets if they are empty', async () => {
await db.setAdd('setsRemoveSet3', ['a']);
await db.setAdd('setsRemoveSet4', ['a']);
await db.setsRemove(['setsRemoveSet3', 'setsRemoveSet4'], 'a');
assert.deepStrictEqual(
await db.exists(['setsRemoveSet3', 'setsRemoveSet4']),
[false, false]
);
});
});