Files
mongo/jstests/sharding/query/agg/agg_sort.js
Steve McClure 1ffbc6c2e9 SERVER-109432: Autofix JS var usage to favor let (#40637)
GitOrigin-RevId: 9674b7db36a0f3f650d39c1e3fb2ad6ff2141cfb
2025-08-28 19:21:01 +00:00

212 lines
7.3 KiB
JavaScript

// Tests that the sort order is obeyed when an aggregation requests sorted results that are
// scattered across multiple shards.
import {ShardingTest} from "jstests/libs/shardingtest.js";
const shardingTest = new ShardingTest({shards: 2});
const db = shardingTest.getDB("test");
const coll = db.sharded_agg_sort;
coll.drop();
assert.commandWorked(
shardingTest.s0.adminCommand({enableSharding: db.getName(), primaryShard: shardingTest.shard1.shardName}),
);
assert.commandWorked(shardingTest.s0.adminCommand({shardCollection: coll.getFullName(), key: {_id: 1}}));
const nDocs = 10;
const yValues = ["abc", "ABC", null, 1, NumberLong(2), NumberDecimal(-20), MinKey, MaxKey, BinData(0, ""), [3, 4]];
const bulkOp = coll.initializeOrderedBulkOp();
for (let i = 0; i < nDocs; ++i) {
bulkOp.insert({_id: i, x: Math.floor(i / 2), y: yValues[i]});
}
assert.commandWorked(bulkOp.execute());
// Split the data into 3 chunks
assert.commandWorked(shardingTest.s0.adminCommand({split: coll.getFullName(), middle: {_id: 3}}));
assert.commandWorked(shardingTest.s0.adminCommand({split: coll.getFullName(), middle: {_id: 6}}));
// Migrate the middle chunk to another shard
assert.commandWorked(
shardingTest.s0.adminCommand({
movechunk: coll.getFullName(),
find: {_id: 5},
to: shardingTest.getOther(shardingTest.getPrimaryShard(db.getName())).name,
}),
);
function assertResultsEqual({actual, expected}) {
const resultsAsString = " actual: " + tojson(actual) + "\n expected: " + tojson(expected);
assert.eq(actual.length, expected.length, `different number of results:\n${resultsAsString}`);
for (let i = 0; i < actual.length; i++) {
assert.eq(actual[i], expected[i], `different results at index ${i}:\n${resultsAsString}`);
}
}
function testSorts() {
// Test a basic sort by _id.
assertResultsEqual({
actual: coll.aggregate([{$sort: {_id: 1}}]).toArray(),
expected: [
{_id: 0, x: 0, y: "abc"},
{_id: 1, x: 0, y: "ABC"},
{_id: 2, x: 1, y: null},
{_id: 3, x: 1, y: 1},
{_id: 4, x: 2, y: NumberLong(2)},
{_id: 5, x: 2, y: NumberDecimal(-20)},
{_id: 6, x: 3, y: MinKey},
{_id: 7, x: 3, y: MaxKey},
{_id: 8, x: 4, y: BinData(0, "")},
{_id: 9, x: 4, y: [3, 4]},
],
});
assertResultsEqual({
actual: coll.aggregate([{$sort: {_id: 1}}, {$project: {_id: 1}}]).toArray(),
expected: new Array(nDocs).fill().map(function (_, index) {
return {_id: index};
}),
});
// Test a compound sort.
assertResultsEqual({
actual: coll.aggregate([{$sort: {x: 1, y: 1}}]).toArray(),
expected: [
{_id: 1, x: 0, y: "ABC"},
{_id: 0, x: 0, y: "abc"},
{_id: 2, x: 1, y: null},
{_id: 3, x: 1, y: 1},
{_id: 5, x: 2, y: NumberDecimal(-20)},
{_id: 4, x: 2, y: NumberLong(2)},
{_id: 6, x: 3, y: MinKey},
{_id: 7, x: 3, y: MaxKey},
{_id: 9, x: 4, y: [3, 4]},
{_id: 8, x: 4, y: BinData(0, "")},
],
});
assertResultsEqual({
actual: coll.aggregate([{$sort: {x: 1, y: 1}}, {$project: {_id: 0, x: 1, y: 1}}]).toArray(),
expected: [
{x: 0, y: "ABC"},
{x: 0, y: "abc"},
{x: 1, y: null},
{x: 1, y: 1},
{x: 2, y: NumberDecimal(-20)},
{x: 2, y: NumberLong(2)},
{x: 3, y: MinKey},
{x: 3, y: MaxKey},
{x: 4, y: [3, 4]},
{x: 4, y: BinData(0, "")},
],
});
// Test a compound sort with a missing field.
assertResultsEqual({
actual: coll.aggregate({$sort: {missing: -1, x: 1, _id: -1}}).toArray(),
expected: [
{_id: 1, x: 0, y: "ABC"},
{_id: 0, x: 0, y: "abc"},
{_id: 3, x: 1, y: 1},
{_id: 2, x: 1, y: null},
{_id: 5, x: 2, y: NumberDecimal(-20)},
{_id: 4, x: 2, y: NumberLong(2)},
{_id: 7, x: 3, y: MaxKey},
{_id: 6, x: 3, y: MinKey},
{_id: 9, x: 4, y: [3, 4]},
{_id: 8, x: 4, y: BinData(0, "")},
],
});
}
testSorts();
assert.commandWorked(coll.createIndex({x: 1}));
testSorts();
assert.commandWorked(coll.createIndex({x: 1, y: 1}));
testSorts();
assert.commandWorked(coll.createIndex({missing: 1, x: -1}));
testSorts();
assert.commandWorked(coll.createIndex({missing: -1, x: 1, _id: -1}));
testSorts();
// Test that a sort including the text score is merged properly in a sharded cluster.
const textColl = db.sharded_agg_sort_text;
assert.commandWorked(shardingTest.s0.adminCommand({shardCollection: textColl.getFullName(), key: {_id: 1}}));
assert.commandWorked(
textColl.insert([
{_id: 0, text: "apple"},
{_id: 1, text: "apple orange banana apple"},
{_id: 2, text: "apple orange"},
{_id: 3, text: "apple orange banana apple apple banana"},
{_id: 4, text: "apple orange banana"},
{_id: 5, text: "apple orange banana apple apple"},
]),
);
// Split the data into 3 chunks
assert.commandWorked(shardingTest.s0.adminCommand({split: textColl.getFullName(), middle: {_id: 2}}));
assert.commandWorked(shardingTest.s0.adminCommand({split: textColl.getFullName(), middle: {_id: 4}}));
// Migrate the middle chunk to another shard
assert.commandWorked(
shardingTest.s0.adminCommand({
movechunk: textColl.getFullName(),
find: {_id: 3},
to: shardingTest.getOther(shardingTest.getPrimaryShard(db.getName())).name,
}),
);
assert.commandWorked(textColl.createIndex({text: "text"}));
assertResultsEqual({
actual: textColl
.aggregate([{$match: {$text: {$search: "apple banana orange"}}}, {$sort: {x: {$meta: "textScore"}}}])
.toArray(),
expected: [
{_id: 3, text: "apple orange banana apple apple banana"},
{_id: 5, text: "apple orange banana apple apple"},
{_id: 1, text: "apple orange banana apple"},
{_id: 4, text: "apple orange banana"},
{_id: 2, text: "apple orange"},
{_id: 0, text: "apple"},
],
});
function assertSortedByMetaField(results) {
for (let i = 0; i < results.length - 1; ++i) {
assert(
results[i].hasOwnProperty("meta"),
`Expected all results to have "meta" field, found one without it at index ${i}`,
);
assert.gte(
results[i].meta,
results[i + 1].meta,
`Expected results to be sorted by "meta" field, descending. Detected unsorted` +
` results at index ${i}, entire result set: ${tojson(results)}`,
);
}
}
assertSortedByMetaField(
textColl
.aggregate([
{$match: {$text: {$search: "apple banana orange"}}},
{$sort: {x: {$meta: "textScore"}}},
{$project: {_id: 0, meta: {$meta: "textScore"}}},
])
.toArray(),
);
assertSortedByMetaField(
textColl
.aggregate([
{$match: {$text: {$search: "apple banana orange"}}},
{$project: {_id: 0, meta: {$meta: "textScore"}}},
{$sort: {meta: -1}},
])
.toArray(),
);
assertSortedByMetaField(
textColl.aggregate([{$sample: {size: 10}}, {$project: {_id: 0, meta: {$meta: "randVal"}}}]).toArray(),
);
shardingTest.stop();