mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-05-06 23:56:04 +02:00
refactor: setObjectBulk to match sortedSetAddBulk
This commit is contained in:
@@ -121,8 +121,7 @@ module.exports = function (Categories) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await db.setObjectBulk(
|
await db.setObjectBulk(
|
||||||
childrenCids.map(cid => `category:${cid}`),
|
childrenCids.map((cid, index) => [`category:${cid}`, { order: index + 1 }])
|
||||||
childrenCids.map((cid, index) => ({ order: index + 1 }))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
cache.del([
|
cache.del([
|
||||||
|
|||||||
@@ -35,20 +35,26 @@ module.exports = function (module) {
|
|||||||
cache.del(key);
|
cache.del(key);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.setObjectBulk = async function (keys, data) {
|
module.setObjectBulk = async function (...args) {
|
||||||
if (!keys.length || !data.length) {
|
let data = args[0];
|
||||||
|
if (!Array.isArray(data) || !data.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (Array.isArray(args[1])) {
|
||||||
|
console.warn('[deprecated] db.setObjectBulk(keys, data) usage is deprecated, please use db.setObjectBulk(data)');
|
||||||
|
// conver old format to new format for backwards compatibility
|
||||||
|
data = args[0].map((key, i) => [key, args[1][i]]);
|
||||||
|
}
|
||||||
|
|
||||||
const writeData = data.map(helpers.serializeData);
|
|
||||||
try {
|
try {
|
||||||
let bulk;
|
let bulk;
|
||||||
keys.forEach((key, i) => {
|
data.forEach((item) => {
|
||||||
if (Object.keys(writeData[i]).length) {
|
const writeData = helpers.serializeData(item[1]);
|
||||||
|
if (Object.keys(writeData).length) {
|
||||||
if (!bulk) {
|
if (!bulk) {
|
||||||
bulk = module.client.collection('objects').initializeUnorderedBulkOp();
|
bulk = module.client.collection('objects').initializeUnorderedBulkOp();
|
||||||
}
|
}
|
||||||
bulk.find({ _key: key }).upsert().updateOne({ $set: writeData[i] });
|
bulk.find({ _key: item[0] }).upsert().updateOne({ $set: writeData });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (bulk) {
|
if (bulk) {
|
||||||
@@ -56,12 +62,12 @@ module.exports = function (module) {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err && err.message.startsWith('E11000 duplicate key error')) {
|
if (err && err.message.startsWith('E11000 duplicate key error')) {
|
||||||
return await module.setObjectBulk(keys, data);
|
return await module.setObjectBulk(data);
|
||||||
}
|
}
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.del(keys);
|
cache.del(data.map(item => item[0]));
|
||||||
};
|
};
|
||||||
|
|
||||||
module.setObjectField = async function (key, field, value) {
|
module.setObjectField = async function (key, field, value) {
|
||||||
|
|||||||
@@ -44,29 +44,30 @@ module.exports = function (module) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.setObjectBulk = async function (keys, data) {
|
module.setObjectBulk = async function (...args) {
|
||||||
if (!keys.length || !data.length) {
|
let data = args[0];
|
||||||
|
if (!Array.isArray(data) || !data.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (Array.isArray(args[1])) {
|
||||||
|
console.warn('[deprecated] db.setObjectBulk(keys, data) usage is deprecated, please use db.setObjectBulk(data)');
|
||||||
|
// conver old format to new format for backwards compatibility
|
||||||
|
data = args[0].map((key, i) => [key, args[1][i]]);
|
||||||
|
}
|
||||||
await module.transaction(async (client) => {
|
await module.transaction(async (client) => {
|
||||||
keys = keys.slice();
|
data = data.filter((item) => {
|
||||||
data = data.filter((d, i) => {
|
if (item[1].hasOwnProperty('')) {
|
||||||
if (d.hasOwnProperty('')) {
|
delete item[1][''];
|
||||||
delete d[''];
|
|
||||||
}
|
}
|
||||||
const keep = !!Object.keys(d).length;
|
return !!Object.keys(item[1]).length;
|
||||||
if (!keep) {
|
|
||||||
keys.splice(i, 1);
|
|
||||||
}
|
|
||||||
return keep;
|
|
||||||
});
|
});
|
||||||
|
const keys = data.map(item => item[0]);
|
||||||
if (!keys.length) {
|
if (!keys.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await helpers.ensureLegacyObjectsType(client, keys, 'hash');
|
await helpers.ensureLegacyObjectsType(client, keys, 'hash');
|
||||||
const dataStrings = data.map(JSON.stringify);
|
const dataStrings = data.map(item => JSON.stringify(item[1]));
|
||||||
await client.query({
|
await client.query({
|
||||||
name: 'setObjectBulk',
|
name: 'setObjectBulk',
|
||||||
text: `
|
text: `
|
||||||
|
|||||||
@@ -36,18 +36,25 @@ module.exports = function (module) {
|
|||||||
cache.del(key);
|
cache.del(key);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.setObjectBulk = async function (keys, data) {
|
module.setObjectBulk = async function (...args) {
|
||||||
if (!keys.length || !data.length) {
|
let data = args[0];
|
||||||
|
if (!Array.isArray(data) || !data.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (Array.isArray(args[1])) {
|
||||||
|
console.warn('[deprecated] db.setObjectBulk(keys, data) usage is deprecated, please use db.setObjectBulk(data)');
|
||||||
|
// conver old format to new format for backwards compatibility
|
||||||
|
data = args[0].map((key, i) => [key, args[1][i]]);
|
||||||
|
}
|
||||||
|
|
||||||
const batch = module.client.batch();
|
const batch = module.client.batch();
|
||||||
keys.forEach((k, i) => {
|
data.forEach((item) => {
|
||||||
if (Object.keys(data[i]).length) {
|
if (Object.keys(item[1]).length) {
|
||||||
batch.hmset(k, data[i]);
|
batch.hmset(item[0], item[1]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await helpers.execBatch(batch);
|
await helpers.execBatch(batch);
|
||||||
cache.del(keys);
|
cache.del(data.map(item => item[0]));
|
||||||
};
|
};
|
||||||
|
|
||||||
module.setObjectField = async function (key, field, value) {
|
module.setObjectField = async function (key, field, value) {
|
||||||
|
|||||||
@@ -70,19 +70,18 @@ Settings.set = async function (hash, values, quiet) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const sortedSetData = [];
|
const sortedSetData = [];
|
||||||
const objectData = { keys: [], data: [] };
|
const objectData = [];
|
||||||
sortedLists.forEach((list) => {
|
sortedLists.forEach((list) => {
|
||||||
const arr = sortedListData[list];
|
const arr = sortedListData[list];
|
||||||
arr.forEach((data, order) => {
|
arr.forEach((data, order) => {
|
||||||
sortedSetData.push([`settings:${hash}:sorted-list:${list}`, order, order]);
|
sortedSetData.push([`settings:${hash}:sorted-list:${list}`, order, order]);
|
||||||
objectData.keys.push(`settings:${hash}:sorted-list:${list}:${order}`);
|
objectData.push([`settings:${hash}:sorted-list:${list}:${order}`, data]);
|
||||||
objectData.data.push(data);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
db.sortedSetAddBulk(sortedSetData),
|
db.sortedSetAddBulk(sortedSetData),
|
||||||
db.setObjectBulk(objectData.keys, objectData.data),
|
db.setObjectBulk(objectData),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -343,8 +343,7 @@ module.exports = function (Posts) {
|
|||||||
post.data.tid = newTid;
|
post.data.tid = newTid;
|
||||||
});
|
});
|
||||||
await db.setObjectBulk(
|
await db.setObjectBulk(
|
||||||
postData.map(p => `post:queue:${p.id}`),
|
postData.map(p => [`post:queue:${p.id}`, { data: JSON.stringify(p.data) }]),
|
||||||
postData.map(p => ({ data: JSON.stringify(p.data) }))
|
|
||||||
);
|
);
|
||||||
cache.del('post-queue');
|
cache.del('post-queue');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,5 +124,5 @@ async function updateUserLastposttimes(uids, topicsData) {
|
|||||||
async function shiftPostTimes(tid, timestamp) {
|
async function shiftPostTimes(tid, timestamp) {
|
||||||
const pids = (await posts.getPidsFromSet(`tid:${tid}:posts`, 0, -1, false));
|
const pids = (await posts.getPidsFromSet(`tid:${tid}:posts`, 0, -1, false));
|
||||||
// Leaving other related score values intact, since they reflect post order correctly, and it seems that's good enough
|
// Leaving other related score values intact, since they reflect post order correctly, and it seems that's good enough
|
||||||
return db.setObjectBulk(pids.map(pid => `post:${pid}`), pids.map((_, idx) => ({ timestamp: timestamp + idx + 1 })));
|
return db.setObjectBulk(pids.map((pid, idx) => [`post:${pid}`, { timestamp: timestamp + idx + 1 }]));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,8 +155,7 @@ module.exports = function (Topics) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
await db.setObjectBulk(
|
await db.setObjectBulk(
|
||||||
topicData.map(t => `topic:${t.tid}`),
|
topicData.map(t => [`topic:${t.tid}`, { tags: t.tags.join(',') }]),
|
||||||
topicData.map(t => ({ tags: t.tags.join(',') }))
|
|
||||||
);
|
);
|
||||||
}, {});
|
}, {});
|
||||||
await Topics.deleteTag(tag);
|
await Topics.deleteTag(tag);
|
||||||
@@ -335,14 +334,11 @@ module.exports = function (Topics) {
|
|||||||
topicTags.push(tag);
|
topicTags.push(tag);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bulkSet.push({ tags: topicTags.join(',') });
|
bulkSet.push([`topic:${t.tid}`, { tags: topicTags.join(',') }]);
|
||||||
});
|
});
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
db.sortedSetAddBulk(bulkAdd),
|
db.sortedSetAddBulk(bulkAdd),
|
||||||
db.setObjectBulk(
|
db.setObjectBulk(bulkSet),
|
||||||
topicData.map(t => `topic:${t.tid}`),
|
|
||||||
bulkSet,
|
|
||||||
),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await Promise.all(tags.map(updateTagCount));
|
await Promise.all(tags.map(updateTagCount));
|
||||||
@@ -363,14 +359,11 @@ module.exports = function (Topics) {
|
|||||||
topicTags.splice(topicTags.indexOf(tag), 1);
|
topicTags.splice(topicTags.indexOf(tag), 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bulkSet.push({ tags: topicTags.join(',') });
|
bulkSet.push([`topic:${t.tid}`, { tags: topicTags.join(',') }]);
|
||||||
});
|
});
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
db.sortedSetRemoveBulk(bulkRemove),
|
db.sortedSetRemoveBulk(bulkRemove),
|
||||||
db.setObjectBulk(
|
db.setObjectBulk(bulkSet),
|
||||||
topicData.map(t => `topic:${t.tid}`),
|
|
||||||
bulkSet,
|
|
||||||
),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await Promise.all(tags.map(updateTagCount));
|
await Promise.all(tags.map(updateTagCount));
|
||||||
|
|||||||
@@ -15,15 +15,13 @@ module.exports = {
|
|||||||
const keys = tids.map(tid => `tid:${tid}:posters`);
|
const keys = tids.map(tid => `tid:${tid}:posters`);
|
||||||
await db.sortedSetsRemoveRangeByScore(keys, '-inf', 0);
|
await db.sortedSetsRemoveRangeByScore(keys, '-inf', 0);
|
||||||
const counts = await db.sortedSetsCard(keys);
|
const counts = await db.sortedSetsCard(keys);
|
||||||
const setKeys = [];
|
const bulkSet = [];
|
||||||
const data = [];
|
|
||||||
for (let i = 0; i < tids.length; i++) {
|
for (let i = 0; i < tids.length; i++) {
|
||||||
if (counts[i] > 0) {
|
if (counts[i] > 0) {
|
||||||
setKeys.push(`topic:${tids[i]}`);
|
bulkSet.push([`topic:${tids[i]}`, { postercount: counts[i] }]);
|
||||||
data.push({ postercount: counts[i] });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await db.setObjectBulk(setKeys, data);
|
await db.setObjectBulk(bulkSet);
|
||||||
}, {
|
}, {
|
||||||
progress: progress,
|
progress: progress,
|
||||||
batchSize: 500,
|
batchSize: 500,
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ module.exports = {
|
|||||||
const tidToCount = _.zipObject(tids, counts);
|
const tidToCount = _.zipObject(tids, counts);
|
||||||
const tidsWithThumbs = tids.filter((t, i) => counts[i] > 0);
|
const tidsWithThumbs = tids.filter((t, i) => counts[i] > 0);
|
||||||
await db.setObjectBulk(
|
await db.setObjectBulk(
|
||||||
tidsWithThumbs.map(tid => `topic:${tid}`),
|
tidsWithThumbs.map(tid => [`topic:${tid}`, { numThumbs: tidToCount[tid] }]),
|
||||||
tidsWithThumbs.map(tid => ({ numThumbs: tidToCount[tid] }))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
progress.incr(tids.length);
|
progress.incr(tids.length);
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ module.exports = {
|
|||||||
}).filter(t => t && t.tags.length);
|
}).filter(t => t && t.tags.length);
|
||||||
|
|
||||||
await db.setObjectBulk(
|
await db.setObjectBulk(
|
||||||
topicsWithTags.map(t => `topic:${t.tid}`),
|
topicsWithTags.map(t => [`topic:${t.tid}`, { tags: t.tags.join(',') }]),
|
||||||
topicsWithTags.map(t => ({ tags: t.tags.join(',') }))
|
|
||||||
);
|
);
|
||||||
await db.deleteAll(tids.map(tid => `topic:${tid}:tags`));
|
await db.deleteAll(tids.map(tid => `topic:${tid}:tags`));
|
||||||
progress.incr(tids.length);
|
progress.incr(tids.length);
|
||||||
|
|||||||
@@ -177,13 +177,9 @@ widgets.setAreas = async function (areas) {
|
|||||||
templates[area.template][area.location] = JSON.stringify(area.widgets);
|
templates[area.template][area.location] = JSON.stringify(area.widgets);
|
||||||
});
|
});
|
||||||
|
|
||||||
const keys = [];
|
await db.setObjectBulk(
|
||||||
const data = [];
|
Object.keys(templates).map(tpl => [`widgets:${tpl}`, templates[tpl]])
|
||||||
Object.keys(templates).forEach((tpl) => {
|
);
|
||||||
keys.push(`widgets:${tpl}`);
|
|
||||||
data.push(templates[tpl]);
|
|
||||||
});
|
|
||||||
await db.setObjectBulk(keys, data);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
widgets.reset = async function () {
|
widgets.reset = async function () {
|
||||||
|
|||||||
@@ -73,36 +73,33 @@ describe('Hash methods', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set multiple keys to different objects', async () => {
|
it('should set multiple keys to different objects', async () => {
|
||||||
const keys = ['bulkKey1', 'bulkKey2'];
|
await db.setObjectBulk([
|
||||||
const data = [{ foo: '1' }, { baz: 'baz' }];
|
['bulkKey1', { foo: '1' }],
|
||||||
|
['bulkKey2', { baz: 'baz' }],
|
||||||
await db.setObjectBulk(keys, data);
|
]);
|
||||||
const result = await db.getObjects(keys);
|
const result = await db.getObjects(['bulkKey1', 'bulkKey2']);
|
||||||
assert.deepStrictEqual(result, data);
|
assert.deepStrictEqual(result, [{ foo: '1' }, { baz: 'baz' }]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not error if object is empty', async () => {
|
it('should not error if object is empty', async () => {
|
||||||
const keys = ['bulkKey3', 'bulkKey4'];
|
await db.setObjectBulk([
|
||||||
const data = [{ foo: '1' }, { }];
|
['bulkKey3', { foo: '1' }],
|
||||||
|
['bulkKey4', { }],
|
||||||
await db.setObjectBulk(keys, data);
|
]);
|
||||||
const result = await db.getObjects(keys);
|
const result = await db.getObjects(['bulkKey3', 'bulkKey4']);
|
||||||
assert.deepStrictEqual(result, [{ foo: '1' }, null]);
|
assert.deepStrictEqual(result, [{ foo: '1' }, null]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update existing object on second call', async () => {
|
it('should update existing object on second call', async () => {
|
||||||
await db.setObjectBulk(['bulkKey3.5'], [{ foo: '1' }]);
|
await db.setObjectBulk([['bulkKey3.5', { foo: '1' }]]);
|
||||||
await db.setObjectBulk(['bulkKey3.5'], [{ baz: '2' }]);
|
await db.setObjectBulk([['bulkKey3.5', { baz: '2' }]]);
|
||||||
const result = await db.getObject('bulkKey3.5');
|
const result = await db.getObject('bulkKey3.5');
|
||||||
assert.deepStrictEqual(result, { foo: '1', baz: '2' });
|
assert.deepStrictEqual(result, { foo: '1', baz: '2' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not error if object is empty', async () => {
|
it('should not error if object is empty', async () => {
|
||||||
const keys = ['bulkKey5'];
|
await db.setObjectBulk([['bulkKey5', {}]]);
|
||||||
const data = [{ }];
|
const result = await db.getObjects(['bulkKey5']);
|
||||||
|
|
||||||
await db.setObjectBulk(keys, data);
|
|
||||||
const result = await db.getObjects(keys);
|
|
||||||
assert.deepStrictEqual(result, [null]);
|
assert.deepStrictEqual(result, [null]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user