Операторы 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)

Ответ 5

Начиная с Mongo 4.0, появился новый оператор агрегации $toDouble который преобразует из различных типов в удвоенные (в данном случае из строки):

// { price: "300.00" }
// { price: "4.2" }
 db.collection.find({ $expr: { $gt: [{ $toDouble: "$price" }, 30] } })
// { price: "300.00" }