Операторы MongoDB $gt/$lt с ценами, хранящимися как строки
Я пытаюсь запросить в моей базе данных цены выше/меньше указанного пользователем числа. В моей базе данных цены хранятся так:
{price: "300.00"}
Согласно документам, это должно работать:
db.products.find({price: {$gt:30.00}}).pretty()
Но я не получил никаких результатов. Я также пытался {price: {$gt:30}}
.
Что мне здесь не хватает?
Это потому, что цены хранятся в виде строки, а не числа в БД? Это можно обойти?
Ответы
Ответ 1
Если вы намерены использовать $gt со строками, вам придется использовать регулярное выражение, что не очень удобно с точки зрения производительности. Легче просто создать новое поле, которое содержит числовое значение цены или изменит этот тип поля на int/double. Также должна работать версия javascript, например:
db.products.find("this.price > 30.00")
поскольку js преобразует его в число перед использованием. Однако индексы не будут работать над этим запросом.
Ответ 2
$gt
- это оператор, который может работать с любым типом:
db.so.drop();
db.so.insert( { name: "Derick" } );
db.so.insert( { name: "Jayz" } );
db.so.find( { name: { $gt: "Fred" } } );
Возврат:
{ "_id" : ObjectId("51ffbe6c16473d7b84172d58"), "name" : "Jayz" }
Если вы хотите сравнить с числом с $gt
или $lt
, тогда значение в вашем документе также должно быть числом. Типы в MongoDB строги и не автоматически конвертировать, как они f.e. будет делать в PHP. Чтобы решить вашу проблему, убедитесь, что вы храните цены в виде чисел (float или int):
db.so.drop();
db.so.insert( { price: 50.40 } );
db.so.insert( { price: 29.99 } );
db.so.find( { price: { $gt: 30 } } );
Возврат:
{ "_id" : ObjectId("51ffbf2016473d7b84172d5b"), "price" : 50.4 }
Ответ 3
В качестве альтернативы вы можете преобразовать значения в Int, в соответствии с:
http://www.quora.com/How-can-I-change-a-field-type-from-String-to-Integer-in-mongodb
var convert = function(document){
var intValue = parseInt(document.field, 10);
db.collection.update(
{_id:document._id},
{$set: {field: intValue}}
);
}
db.collection.find({field: {$type:2}},{field:1}).forEach(convert)
Ответ 4
Если у вас более новая версия mongodb, вы можете сделать это:
$expr: {
$gt: [
{ $convert: { input: '$price', to: 'decimal' } },
{ $convert: { input: '0.0', to: 'decimal' } }
]
}
Оператор $ expr: https://docs.mongodb.com/manual/reference/operator/query/expr/
$ convert opetator: https://docs.mongodb.com/manual/reference/operator/aggregation/convert/index.html
Ответ 5
Начиная с Mongo 4.0
, появился новый оператор агрегации $toDouble
который преобразует из различных типов в удвоенные (в данном случае из строки):
// { price: "300.00" }
// { price: "4.2" }
db.collection.find({ $expr: { $gt: [{ $toDouble: "$price" }, 30] } })
// { price: "300.00" }