Многие многочисленные дубликаты этого вопроса задают вопрос о влиянии округления с плавающей запятой на конкретные числа. На практике легче понять, как это работает, глядя на точные результаты вычислений, а не просто на чтение. Некоторые языки предоставляют способы сделать это - например, преобразование float
или double
в BigDecimal
в Java.
Так как это вопрос, связанный с языком, ему нужны языковые агностические инструменты, такие как как Десятичный преобразование с плавающей запятой .
Применяя его к числам в вопросе, рассматриваемым как удваивает:
0,1 преобразуется в 0,1000000000000000055511151231257827021181583404541015625,
0,2 преобразуется в 0.200000000000000011102230246251565404236316680908203125,
0,3 конвертируется в 0,29999999999999999989897769753748434595763683319091796875 и
0,30000000000000004 преобразуется в 0,3000000000000000444089209850062616169452667236328125.
Добавление первых двух чисел вручную или в десятичный калькулятор, такой как Full Precision Calculator , показывает точную сумму фактических входов: 0.3000000000000000166533453693773481063544750213623046875.
Если округлить до эквивалента 0,3, ошибка округления будет 0.0000000000000000277555756156289135105907917022705078125. Округление до эквивалента 0,30000000000000004 также дает ошибку округления 0,0000000000000000277555756156289135105907917022705078125.
Возвращаясь к конвертеру с плавающей запятой, необработанный шестнадцатеричный показатель для 0.30000000000000004 равен 3fd3333333333334, который заканчивается четной цифрой и, следовательно, является правильным результатом.
Обновление:
Начиная с v2.0 данных Spring, вы можете сделать это:
SampleOperation matchStage = Aggregation.sample(5);
Aggregation aggregation = Aggregation.newAggregation(sampleStage);
AggregationResults<OutType> output = mongoTemplate.aggregate(aggregation, "collectionName", OutType.class);
Оригинальный ответ:
Уровни абстракции как spring-mongo, всегда будут отставать от выпущенных функций сервера. Таким образом, вам лучше всего самостоятельно структурировать структуру документа BSON для этапа конвейера.
Реализовать в пользовательском классе:
public class CustomAggregationOperation implements AggregationOperation {
private DBObject operation;
public CustomAggregationOperation (DBObject operation) {
this.operation = operation;
}
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return context.getMappedObject(operation);
}
}
И затем использовать в своем коде:
Aggregation aggregation = newAggregation(
new CutomAggregationOperation(
new BasicDBObject(
"$sample",
new BasicDBObject( "size", 15 )
)
)
);
Так как это реализует AggregationOperation
, это хорошо работает с вспомогательными методами вывода операций. i.e:
Aggregation aggregation = newAggregation(
// custom pipeline stage
new CutomAggregationOperation(
new BasicDBObject(
"$sample",
new BasicDBObject( "size", 15 )
)
),
// Standard match pipeline stage
match(
Criteria.where("myDate")
.gte(new Date(new Long("949384052490")))
.lte(new Date(new Long("1448257684431")))
)
);
Итак, все это просто объект BSON в конце дня. Это всего лишь вопрос об использовании оболочки интерфейса, чтобы методы класса в Spring-Mongo интерпретировали результат и правильно определили ваш BSON-объект.
Blakes Seven ответил на это правильно, однако я хочу предложить более эффективную реализацию AggregationOperation, которая следует за стандартной реализацией Spring
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.util.Assert;
public class SampleOperation implements AggregationOperation {
private int size;
public SampleOperation(int size) {
Assert.isTrue(size > 0, " Size must be positive!");
this.size = size;
}
public AggregationOperation setSize(int size) {
Assert.isTrue(size > 0, " Size must be positive!");
this.size = size;
return this;
}
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return new BasicDBObject("$sample", context.getMappedObject(Criteria.where("size").is(size).getCriteriaObject()));
}
}
. После этого вы можете создать объект SampleOperation с помощью конструктора или позже изменить размер его с помощью метода setSize()
и применить его к функции aggregate()
как обычно.
Обновление: в SpringBoot 2.0.0+ и Spring Framework 5.0: Spring Mongo drop DBObject
и заменить на org.bson.Document
, поэтому последнее прошлое должно обновляться как:
@Override
public Document toDocument(AggregationOperationContext aggregationOperationContext) {
return new Document("$sample", aggregationOperationContext.getMappedObject(Criteria.where("size").is(size).getCriteriaObject()));
}
И удалить @Override toDBObject