Files
mongo/jstests/aggregation/sources/densify/decimal.js

162 lines
4.7 KiB
JavaScript

/**
* Test that $densify works with Decimal128 type values.
* @tags: [
* # Needed as $densify is a 51 feature.
* requires_fcv_51,
* ]
*/
(function() {
"use strict";
load("jstests/aggregation/extras/utils.js"); // For arrayEq.
function buildErrorString(found, expected) {
return "Expected:\n" + tojson(expected) + "\nGot:\n" + tojson(found);
}
const coll = db[jsTestName()];
coll.drop();
assert.commandWorked(coll.insert([
{val: NumberDecimal(0)},
{val: NumberDecimal(10)},
]));
let pipeline = [{$project: {_id: 0}}, {$densify: {field: "val", range: {step: 1, bounds: "full"}}}];
let expectedResult = [];
for (let i = 0; i <= 10; i++) {
expectedResult.push({val: NumberDecimal(i)});
}
let result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
// Add a double in the middle of the range.
assert.commandWorked(coll.insert({val: 5}));
expectedResult = [];
// $densify uses the last type seen for generated documents.
for (let i = 0; i <= 10; i++) {
if (i < 5 || i == 10) {
expectedResult.push({val: NumberDecimal(i)});
} else {
expectedResult.push({val: i});
}
}
result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
// Run the same test, but with a Decimal step.
pipeline = [
{$project: {_id: 0}},
{$densify: {field: "val", range: {step: NumberDecimal(1), bounds: "full"}}}
];
expectedResult = [];
for (let i = 0; i <= 10; i++) {
if (i != 5) {
expectedResult.push({val: NumberDecimal(i)});
} else {
expectedResult.push({val: i});
}
}
result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
// Run the same test, but with decimals instead of integers.
coll.drop();
assert.commandWorked(coll.insert([
{val: NumberDecimal(0)},
{val: .5},
{val: NumberDecimal(1)},
]));
pipeline = [{$project: {_id: 0}}, {$densify: {field: "val", range: {step: .1, bounds: "full"}}}];
// Note that all the results after .5 may not be precisely on the step, but instead be off by a
// vanishingly small amount.
expectedResult = [
{val: NumberDecimal(0)},
{val: NumberDecimal(".1")},
{val: NumberDecimal(".2")},
{val: NumberDecimal(".3")},
{val: NumberDecimal(".4")},
{val: .5},
{val: .6},
{val: .7},
{val: .7999999999999999},
{val: .8999999999999999},
{val: .9999999999999999},
{val: NumberDecimal(1)},
];
result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
// Repeat with a NumberDecimal step
pipeline = [
{$project: {_id: 0}},
{$densify: {field: "val", range: {step: NumberDecimal(".1"), bounds: "full"}}}
];
expectedResult = [
{val: NumberDecimal(0)},
{val: NumberDecimal(".1")},
{val: NumberDecimal(".2")},
{val: NumberDecimal(".3")},
{val: NumberDecimal(".4")},
{val: .5},
{val: NumberDecimal(".6")},
{val: NumberDecimal(".7")},
{val: NumberDecimal(".8")},
{val: NumberDecimal(".9")},
{val: NumberDecimal(1)},
];
result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
// If the step is Decimal128, return Decimal128.
coll.drop();
assert.commandWorked(coll.insert([
{val: 0},
{val: 1},
]));
pipeline = [
{$project: {_id: 0}},
{$densify: {field: "val", range: {step: NumberDecimal(.001), bounds: "full"}}},
// No need to check every value.
{$limit: 2},
];
result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, [{val: 0}, {val: NumberDecimal(.001)}]));
// Decimal bounds fail if step is not decimal.
pipeline = [
{$project: {_id: 0}},
{$densify: {field: "val", range: {step: .1, bounds: [NumberDecimal(.1), NumberDecimal(.9)]}}},
// No need to check every value.
{$limit: 3},
];
assert.commandFailedWithCode(
db.runCommand({aggregate: coll.getName(), pipeline: pipeline, cursor: {}}), 5876900);
// Verify that if 'step' is not representable as a double, precision is not lost during computation.
const preciseStep = NumberDecimal(".1243568735894448377382");
const preciseStepTimesTwo = NumberDecimal(".2487137471788896754764");
const preciseStepTimesThree = NumberDecimal(".3730706207683345132146");
pipeline = [
{$project: {_id: 0}},
{$densify: {field: "val", range: {step: preciseStep, bounds: "full"}}},
// No need to check every value.
{$limit: 4},
];
result = coll.aggregate(pipeline).toArray();
expectedResult = [
{val: 0},
{val: preciseStep},
{val: preciseStepTimesTwo},
{val: preciseStepTimesThree},
];
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
})();